STIR 6.4.0
BackProjectorByBinUsingInterpolation_3DCho.cxx
Go to the documentation of this file.
1//
2//
3/*
4 Copyright (C) 2000 PARAPET partners
5 Copyright (C) 2000- 2008, Hammersmith Imanet Ltd
6 This file is part of STIR.
7
8 SPDX-License-Identifier: Apache-2.0 AND License-ref-PARAPET-license
9
10 See STIR/LICENSE.txt for details
11*/
31
32// enable this variable if you need to handle very oblique LORs
33#define MOREZ
34//#define ALTERNATIVE
35/*
36
37 These functions use a 3D version of Cho's algorithm for backprojecting
38 incrementally.
39 See M. Egger's thesis for details.
40
41 They use the following symmetries:
42 - opposite ring difference
43 - views : view, view+90 degrees, 180 degrees - view, 90 degrees - view
44 - s,-s symmetry (while being careful when s==0 to avoid self-symmetric
45 cases)
46
47 For historical reasons, 'axial_pos_num' is here called 'ring'.
48
49 Note: encoding used in Proj2424
50 Proj2424[n][f][ms][b]
51 n : 1 : negative delta; 0 : positive delta
52 f : 0 : view; 1 : pi/2-view; 2 : pi/2+view; 3: pi-view
53 ms : 1 : negative s; 0 : positive s
54 b : 1 : r1,s; 2: r2,s+1; 3: r2,s 4: r1,s+1
55 where r1=ring0, r2=ring0+1 when
56 (n==ms && f==0||2) || (n!=ms && f==1||3)
57 and the role of r1,r2 are reversed in the other cases
58
59 Naming conventions for the incremental variables:
60 n==0 && ms==0: A'f'
61 n==0 && ms==1: P'f'
62 n==1 && ms==0: A'f'n
63 n==1 && ms==1: P'f'n
64
65 Symmetries:
66 s-> -s changes dz->1-dz, ds->-ds
67 view->pi/2+view changes dz->dz, ds->ds
68 view->pi/2-view changes dz->1-dz, ds->ds
69 delta->-delta changes dz->1-dz, ds->ds
70 */
71
72#include "stir/ProjDataInfo.h"
77#include "stir/round.h"
78#include "stir/Succeeded.h"
79#include "stir/warning.h"
80#include "stir/error.h"
81#include <math.h>
82
83#include <algorithm>
84using std::min;
85using std::max;
86/*
87 KT 22/05/98 drastic revision
88
89cosmetic changes:
90 - removed lots of local variables which were not used (or are not used
91 anymore)
92 - moved most declarations of variables to the place where they are
93 initialised, and add const when possible
94 - added grouping {} to make variables local
95 - translated German and Afrikaans comments and added new comments
96
97 - reordered the main loop to avoid repeating the 'voxel-updating' code
98 - moved the initialisation code (common to all symmetry cases) into the
99 find_start_values() function
100
101bugs removed:
102 - handle self-symmetric case at s==0 properly, this was only correct in
103 the 45 degrees case. This removed most of the bright spot in the
104 central pixel.
105
106 - changed the condition to break out of the loop to avoid early stopping,
107 which gave artifacts at the border
108
109 - attempt to take into account that calculations are done with finite precision
110 There used to be 'random' misplacements of data into neighboring voxels,
111 this happened in the central pixel and at 45 and 135 degrees.
112 * use double to prevent rounding errors, necessary for incremental
113 quantities
114 * change all comparisons with 0 to comparisons with a small number
115 'epsilon'
116
117increased precision:
118 - use double for invariants as well
119 (otherwise computations of incremental constants would mean promoting
120 floats to doubles all the time)
121
122speed-up
123 - all these changes resulted in an (unexpected) speed-up of about a factor 2
124
125 KT&CL 22/12/99
126span works now by introducing offsets
127
128 KT&SM
129introduced MOREZ to handle very oblique segments. This handles the case where Z
130needs to be incremented more than once to find the next voxel in the beam
131
132 KT 25/09/2001
133make sure things are ok for any image size. The main change is
134to let find_start_values return Succeeded::no if there's no voxel in
135the FOV for this partiuclar tube. If so, we'll just exit.
136
137TODO:
138solve remaining issues of rounding errors (see backproj2D)
139
140if we never parallelise 'beyond' viewgram level (that is, always execute
141the calling back_project() and these functions at the same processor),
142there is probably no point in using the Projptr parameter, and we could
143use the viewgrams directly.
144Indeed, each element in Projptr is accessed 2 (sometimes 3) times only. The
145compiler probably optimises this to 1 (sometimes 2) accesses only.
146So, it could be more expensive to construct the Projptr and fill it in from the
147viewgrams, compared to use the viewgrams directly.
148*/
149
150START_NAMESPACE_STIR
151
152static const double epsilon = 1e-10;
153
154/*
155 This declares a local function that finds the first voxel in the beam, and
156 associated ds,dz etc.
157 It is implemented at the end of the file.
158
159 image_rad: half the image size (in pixels)
160 d_sl : z-voxel size (in mm)
161
162 It returns Succeeded::no when it couldn't find any voxel in the beam.
163 */
164
165// KT 25/09/2001 changed return value
166static Succeeded find_start_values(const shared_ptr<const ProjDataInfoCylindricalArcCorr> proj_data_info_sptr,
167 const float delta,
168 const double cphi,
169 const double sphi,
170 const int s,
171 const int ring0,
172 const float image_rad,
173 const double d_sl,
174 int& X1,
175 int& Y1,
176 int& Z1,
177 double& ds,
178 double& dz,
179 double& dzhor,
180 double& dzvert,
181 const float num_planes_per_axial_pos,
182 const float axial_pos_to_z_offset);
183
184inline void
185check_values(const shared_ptr<const ProjDataInfoCylindricalArcCorr> proj_data_info_sptr,
186 const float delta,
187 const double cphi,
188 const double sphi,
189 const int s,
190 const int ring0,
191 const int X1,
192 const int Y1,
193 const int Z1,
194 const double ds,
195 const double dz,
196 const float num_planes_per_axial_pos,
197 const float axial_pos_to_z_offset)
198{
199#ifdef BPINT_CHECK
200 const double d_xy = proj_data_info_sptr->get_tangential_sampling();
201
202 const double R2 = square(proj_data_info_sptr->get_ring_radius());
203 /* Radius of scanner squared in Pixel^2 */
204 const double R2p = R2 / d_xy / d_xy;
205 // TODO remove assumption
206 const int num_planes_per_physical_ring = 2;
207
208 const double t = s + 0.5; /* In a beam, not on a ray */
209 // t=X1*cphi+Y1*sphi;
210 // ds=t-s;
211
212 const double new_ds = X1 * cphi + Y1 * sphi - s; // Eq 6.13 in Egger thsis
213 const double root = sqrt(R2p - t * t); // CL 26/10/98 Put it back the original formula as before it was root=sqrt(R2p-s*s)
214 // Eq 6.15 from Egger Thesis
215 const double z = (Z1 - num_planes_per_physical_ring * delta / 2 * ((-X1 * sphi + Y1 * cphi) / root + 1) - axial_pos_to_z_offset)
216 / num_planes_per_axial_pos;
217 const double new_dz = z - ring0;
218
219 if (fabs(ds - new_ds) > .005 || fabs(dz - new_dz) > .005)
220 {
221 warning("Difference ds (%g,%g) dz (%g,%g) at X=%d,Y=%d,Z=%d\n", ds, new_ds, dz, new_dz, X1, Y1, Z1);
222 }
223#endif // BPINT_CHECK
224}
225
226/****************************************************************************
227
228 backproj3D_Cho_view_viewplus90 backprojects 4 beams related by
229 symmetry (see bckproj.h)
230
231 *****************************************************************************/
232
233// KT 22/05/98 new, but extracted from backproj3D_ChoView45
234// (which used to be called Backproj_Cho_Symstheta_Phiplus90s0_P)
235void
236BackProjectorByBinUsingInterpolation::
237#if PIECEWISE_INTERPOLATION
238 piecewise_linear_interpolation_backproj3D_Cho_view_viewplus90
239#else
240 linear_interpolation_backproj3D_Cho_view_viewplus90
241#endif
242 (Array<4, float> const& Projptr,
243 VoxelsOnCartesianGrid<float>& image,
244 const shared_ptr<const ProjDataInfoCylindricalArcCorr> proj_data_info_sptr,
245 float delta,
246 const double cphi,
247 const double sphi,
248 int s,
249 int ring0,
250 const int num_planes_per_axial_pos,
251 const float axial_pos_to_z_offset)
252{
253 // KT 04/05/2000 new check
254#if PIECEWISE_INTERPOLATION
255 if (num_planes_per_axial_pos == 1 && delta != 0)
256 error("This version of the backprojector cannot be used for span>1. \
257Recompile %s with PIECEWISE_INTERPOLATION=0",
258 __FILE__);
259#else
260# ifdef ALTERNATIVE
261 // TODO
262 if (num_planes_per_axial_pos == 1 && delta != 0)
263 error("This version of the backprojector cannot be used for span>1. \
264Recompile %s with ALTERNATIVE not #defined",
265 __FILE__);
266# endif
267#endif
268
269#ifndef MOREZ
270 // below test was too conservative. We have to adjust it a bit
271# error times sqrt(2)/iets met t
272 /* Check if delta is not too large. If the condition below is violated,
273 z might have to be incremented more than once to remain in the beam.
274 To do this, the code would have to be modified with while() instead of if().
275 As this will slow it down, we just abort at the moment.
276 */
277
278 if (delta * proj_data_info_sptr_info_cyl_ptr->get_tangential_sampling() / proj_data_info_sptr_info_cyl_ptr->get_ring_radius()
279 > 1)
280 {
281 error("This backprojector cannot handle such oblique segments: delta = %g. Sorry.\n", delta);
282 }
283#endif
284
285 // conditions on searching flow
286 assert(cphi >= 0 - .001);
287 assert(sphi >= 0 - .001);
288 assert(cphi + sphi >= 1 - .001);
289
290 double dzvert, dzhor, ds;
291 double dsdiag, dzdiag, dz;
292 int X, Y, Z, Q;
293
294 const float ring_unit = 1. / num_planes_per_axial_pos;
295
296 // in our current coordinate system, the following constant is always 2
297 // TODO remove assumption
298 const int num_planes_per_physical_ring = 2;
299 assert(fabs(image.get_voxel_size().z() * num_planes_per_physical_ring / proj_data_info_sptr->get_ring_spacing() - 1) < 10E-4);
300
301 /* FOV radius in voxel units */
302 // KT 20/06/2001 change calculation of FOV such that even sized image will work
303 const float fovrad_in_mm = min((min(image.get_max_x(), -image.get_min_x())) * image.get_voxel_size().x(),
304 (min(image.get_max_y(), -image.get_min_y())) * image.get_voxel_size().y());
305 const float image_rad = fovrad_in_mm / image.get_voxel_size().x() - 2;
306 // const int image_rad = (int)((image.get_x_size()-1)/2);
307
308 // KT 20/06/2001 allow min_z!=0 in all comparisons below
309 const int minplane = image.get_min_z();
310 const int maxplane = image.get_max_z();
311
312 if (find_start_values(proj_data_info_sptr,
313 delta,
314 cphi,
315 sphi,
316 s,
317 ring0,
318 image_rad,
319 image.get_voxel_size().z(),
320 X,
321 Y,
322 Z,
323 ds,
324 dz,
325 dzhor,
326 dzvert,
327 num_planes_per_axial_pos,
328 axial_pos_to_z_offset)
329 == Succeeded::no)
330 {
331 // no voxels in the beam
332 return;
333 }
334
335 /*
336 The formulas below give the values to update a pixel.
337 Things are then complicated by optimising this backprojection
338 by 'incrementalising' the formulas.
339 // linear (original) interpolation
340 double UpA0=Projptr[0][0][0][1]+ds*K1A0+dz*K2A0;
341 image[Z][Y][X]+= (UpA0+dsdz*K3A0);
342
343 // new interpolation
344 double A0a0 = Projptr[0][0][0][1]+ds*K1A0;
345 double A0a1 = Projptr[0][0][0][3]+ds*(K1A0+K3A0);
346 double UpA0 = 2*(Projptr[0][0][0][1]+ds*K1A0+dz*K2A0) - (A0a0 + A0a1)/2;
347 image[Z][Y][X]+= (dz <= 0.25) ? A0a0 : UpA0+twodsdz*K3A0;
348
349 incremental changes:
350 // original interpolation
351 UpA0inc=dsinc*K1A0+dzinc*K2A0;
352 // new interpolation
353 A0a0inc = dsinc*K1A0;
354 A0a1inc = dsinc*(K1A0+K3A0);
355 UpA0inc = A0a0inc - A0a1inc/2 +2*dzinc*K2A0
356
357*/
358
359 // K1, K2, K3 invariants
360
361 const double K1A0 = Projptr[0][0][0][2] - Projptr[0][0][0][1];
362 const double K2A0 = Projptr[0][0][0][3] - Projptr[0][0][0][1];
363 const double K3A0 = Projptr[0][0][0][4] - Projptr[0][0][0][2] - K2A0;
364 const double K1A2 = Projptr[0][2][0][2] - Projptr[0][2][0][1];
365 const double K2A2 = Projptr[0][2][0][3] - Projptr[0][2][0][1];
366 const double K3A2 = Projptr[0][2][0][4] - Projptr[0][2][0][2] - K2A2;
367
368 const double K1A0n = Projptr[1][0][0][2] - Projptr[1][0][0][1];
369 const double K2A0n = Projptr[1][0][0][3] - Projptr[1][0][0][1];
370 const double K3A0n = Projptr[1][0][0][4] - Projptr[1][0][0][2] - K2A0n;
371 const double K1A2n = Projptr[1][2][0][2] - Projptr[1][2][0][1];
372 const double K2A2n = Projptr[1][2][0][3] - Projptr[1][2][0][1];
373 const double K3A2n = Projptr[1][2][0][4] - Projptr[1][2][0][2] - K2A2n;
374
375 const double K1P0 = Projptr[0][0][1][2] - Projptr[0][0][1][1];
376 const double K2P0 = Projptr[0][0][1][3] - Projptr[0][0][1][1];
377 const double K3P0 = Projptr[0][0][1][4] - Projptr[0][0][1][2] - K2P0;
378 const double K1P2 = Projptr[0][2][1][2] - Projptr[0][2][1][1];
379 const double K2P2 = Projptr[0][2][1][3] - Projptr[0][2][1][1];
380 const double K3P2 = Projptr[0][2][1][4] - Projptr[0][2][1][2] - K2P2;
381
382 const double K1P0n = Projptr[1][0][1][2] - Projptr[1][0][1][1];
383 const double K2P0n = Projptr[1][0][1][3] - Projptr[1][0][1][1];
384 const double K3P0n = Projptr[1][0][1][4] - Projptr[1][0][1][2] - K2P0n;
385 const double K1P2n = Projptr[1][2][1][2] - Projptr[1][2][1][1];
386 const double K2P2n = Projptr[1][2][1][3] - Projptr[1][2][1][1];
387 const double K3P2n = Projptr[1][2][1][4] - Projptr[1][2][1][2] - K2P2n;
388
389#if !PIECEWISE_INTERPOLATION
390
391 const double ZplusKorrA0 = ring_unit * K2A0;
392 const double ZplusKorrA2 = ring_unit * K2A2;
393
394 const double ZplusKorrA0n = ring_unit * K2A0n;
395 const double ZplusKorrA2n = ring_unit * K2A2n;
396
397 const double ZplusKorrP0 = ring_unit * K2P0;
398 const double ZplusKorrP2 = ring_unit * K2P2;
399
400 const double ZplusKorrP0n = ring_unit * K2P0n;
401 const double ZplusKorrP2n = ring_unit * K2P2n;
402
403 // V, H, D invariants
404
405 const double VA0 = dzvert * K2A0 + sphi * K1A0;
406 const double HA0 = dzhor * K2A0 - cphi * K1A0;
407 const double DA0 = VA0 + HA0;
408 const double VZA0 = VA0 + ring_unit * K2A0;
409 const double HZA0 = HA0 + ring_unit * K2A0;
410 const double DZA0 = DA0 + ring_unit * K2A0;
411 const double VA2 = dzvert * K2A2 + sphi * K1A2;
412 const double HA2 = dzhor * K2A2 - cphi * K1A2;
413 const double DA2 = VA2 + HA2;
414 const double VZA2 = VA2 + ring_unit * K2A2;
415 const double HZA2 = HA2 + ring_unit * K2A2;
416 const double DZA2 = DA2 + ring_unit * K2A2;
417
418 const double VA0n = dzvert * K2A0n + sphi * K1A0n;
419 const double HA0n = dzhor * K2A0n - cphi * K1A0n;
420 const double DA0n = VA0n + HA0n;
421 const double VZA0n = VA0n + ring_unit * K2A0n;
422 const double HZA0n = HA0n + ring_unit * K2A0n;
423 const double DZA0n = DA0n + ring_unit * K2A0n;
424 const double VA2n = dzvert * K2A2n + sphi * K1A2n;
425 const double HA2n = dzhor * K2A2n - cphi * K1A2n;
426 const double DA2n = VA2n + HA2n;
427 const double VZA2n = VA2n + ring_unit * K2A2n;
428 const double HZA2n = HA2n + ring_unit * K2A2n;
429 const double DZA2n = DA2n + ring_unit * K2A2n;
430
431 const double VP0 = dzvert * K2P0 + sphi * K1P0;
432 const double HP0 = dzhor * K2P0 - cphi * K1P0;
433 const double DP0 = VP0 + HP0;
434 const double VZP0 = VP0 + ring_unit * K2P0;
435 const double HZP0 = HP0 + ring_unit * K2P0;
436 const double DZP0 = DP0 + ring_unit * K2P0;
437 const double VP2 = dzvert * K2P2 + sphi * K1P2;
438 const double HP2 = dzhor * K2P2 - cphi * K1P2;
439 const double DP2 = VP2 + HP2;
440 const double VZP2 = VP2 + ring_unit * K2P2;
441 const double HZP2 = HP2 + ring_unit * K2P2;
442 const double DZP2 = DP2 + ring_unit * K2P2;
443
444 const double VP0n = dzvert * K2P0n + sphi * K1P0n;
445 const double HP0n = dzhor * K2P0n - cphi * K1P0n;
446 const double DP0n = VP0n + HP0n;
447 const double VZP0n = VP0n + ring_unit * K2P0n;
448 const double HZP0n = HP0n + ring_unit * K2P0n;
449 const double DZP0n = DP0n + ring_unit * K2P0n;
450 const double VP2n = dzvert * K2P2n + sphi * K1P2n;
451 const double HP2n = dzhor * K2P2n - cphi * K1P2n;
452 const double DP2n = VP2n + HP2n;
453 const double VZP2n = VP2n + ring_unit * K2P2n;
454 const double HZP2n = HP2n + ring_unit * K2P2n;
455 const double DZP2n = DP2n + ring_unit * K2P2n;
456
457 // Initial values of update values (Up)
458
459 double UpA0 = Projptr[0][0][0][1] + ds * K1A0 + dz * K2A0;
460 double UpA2 = Projptr[0][2][0][1] + ds * K1A2 + dz * K2A2;
461
462 double UpA0n = Projptr[1][0][0][1] + ds * K1A0n + dz * K2A0n;
463 double UpA2n = Projptr[1][2][0][1] + ds * K1A2n + dz * K2A2n;
464
465 double UpP0 = Projptr[0][0][1][1] + ds * K1P0 + dz * K2P0;
466 double UpP2 = Projptr[0][2][1][1] + ds * K1P2 + dz * K2P2;
467
468 double UpP0n = Projptr[1][0][1][1] + ds * K1P0n + dz * K2P0n;
469 double UpP2n = Projptr[1][2][1][1] + ds * K1P2n + dz * K2P2n;
470
471#else // PIECEWISE_INTERPOLATION
472
473 const double ZplusKorrA0 = K2A0;
474 const double ZplusKorrA2 = K2A2;
475
476 const double ZplusKorrA0n = K2A0n;
477 const double ZplusKorrA2n = K2A2n;
478
479 const double ZplusKorrP0 = K2P0;
480 const double ZplusKorrP2 = K2P2;
481
482 const double ZplusKorrP0n = K2P0n;
483 const double ZplusKorrP2n = K2P2n;
484
485 // V, H, D invariants
486
487 const double VA0a0 = +sphi * K1A0;
488 const double HA0a0 = -cphi * K1A0;
489 const double DA0a0 = VA0a0 + HA0a0;
490 const double VA2a0 = +sphi * K1A2;
491 const double HA2a0 = -cphi * K1A2;
492 const double DA2a0 = VA2a0 + HA2a0;
493
494 const double VA0na0 = +sphi * K1A0n;
495 const double HA0na0 = -cphi * K1A0n;
496 const double DA0na0 = VA0na0 + HA0na0;
497 const double VA2na0 = +sphi * K1A2n;
498 const double HA2na0 = -cphi * K1A2n;
499 const double DA2na0 = VA2na0 + HA2na0;
500
501 const double VP0a0 = +sphi * K1P0;
502 const double HP0a0 = -cphi * K1P0;
503 const double DP0a0 = VP0a0 + HP0a0;
504 const double VP2a0 = +sphi * K1P2;
505 const double HP2a0 = -cphi * K1P2;
506 const double DP2a0 = VP2a0 + HP2a0;
507
508 const double VP0na0 = +sphi * K1P0n;
509 const double HP0na0 = -cphi * K1P0n;
510 const double DP0na0 = VP0na0 + HP0na0;
511 const double VP2na0 = +sphi * K1P2n;
512 const double HP2na0 = -cphi * K1P2n;
513 const double DP2na0 = VP2na0 + HP2na0;
514
515 const double VA0a1 = +sphi * (K1A0 + K3A0);
516 const double HA0a1 = -cphi * (K1A0 + K3A0);
517 const double DA0a1 = VA0a1 + HA0a1;
518 const double VA2a1 = +sphi * (K1A2 + K3A2);
519 const double HA2a1 = -cphi * (K1A2 + K3A2);
520 const double DA2a1 = VA2a1 + HA2a1;
521
522 const double VA0na1 = +sphi * (K1A0n + K3A0n);
523 const double HA0na1 = -cphi * (K1A0n + K3A0n);
524 const double DA0na1 = VA0na1 + HA0na1;
525 const double VA2na1 = +sphi * (K1A2n + K3A2n);
526 const double HA2na1 = -cphi * (K1A2n + K3A2n);
527 const double DA2na1 = VA2na1 + HA2na1;
528
529 const double VP0a1 = +sphi * (K1P0 + K3P0);
530 const double HP0a1 = -cphi * (K1P0 + K3P0);
531 const double DP0a1 = VP0a1 + HP0a1;
532 const double VP2a1 = +sphi * (K1P2 + K3P2);
533 const double HP2a1 = -cphi * (K1P2 + K3P2);
534 const double DP2a1 = VP2a1 + HP2a1;
535
536 const double VP0na1 = +sphi * (K1P0n + K3P0n);
537 const double HP0na1 = -cphi * (K1P0n + K3P0n);
538 const double DP0na1 = VP0na1 + HP0na1;
539 const double VP2na1 = +sphi * (K1P2n + K3P2n);
540 const double HP2na1 = -cphi * (K1P2n + K3P2n);
541 const double DP2na1 = VP2na1 + HP2na1;
542
543 const double VA0 = VA0a0 * 1.5 - VA0a1 / 2 + 2 * dzvert * K2A0;
544 const double HA0 = HA0a0 * 1.5 - HA0a1 / 2 + 2 * dzhor * K2A0;
545 const double DA0 = VA0 + HA0;
546 const double VZA0 = VA0 + K2A0;
547 const double HZA0 = HA0 + K2A0;
548 const double DZA0 = DA0 + K2A0;
549 const double VA2 = VA2a0 * 1.5 - VA2a1 / 2 + 2 * dzvert * K2A2;
550 const double HA2 = HA2a0 * 1.5 - HA2a1 / 2 + 2 * dzhor * K2A2;
551 const double DA2 = VA2 + HA2;
552 const double VZA2 = VA2 + K2A2;
553 const double HZA2 = HA2 + K2A2;
554 const double DZA2 = DA2 + K2A2;
555
556 const double VA0n = VA0na0 * 1.5 - VA0na1 / 2 + 2 * dzvert * K2A0n;
557 const double HA0n = HA0na0 * 1.5 - HA0na1 / 2 + 2 * dzhor * K2A0n;
558 const double DA0n = VA0n + HA0n;
559 const double VZA0n = VA0n + K2A0n;
560 const double HZA0n = HA0n + K2A0n;
561 const double DZA0n = DA0n + K2A0n;
562 const double VA2n = VA2na0 * 1.5 - VA2na1 / 2 + 2 * dzvert * K2A2n;
563 const double HA2n = HA2na0 * 1.5 - HA2na1 / 2 + 2 * dzhor * K2A2n;
564 const double DA2n = VA2n + HA2n;
565 const double VZA2n = VA2n + K2A2n;
566 const double HZA2n = HA2n + K2A2n;
567 const double DZA2n = DA2n + K2A2n;
568
569 const double VP0 = VP0a0 * 1.5 - VP0a1 / 2 + 2 * dzvert * K2P0;
570 const double HP0 = HP0a0 * 1.5 - HP0a1 / 2 + 2 * dzhor * K2P0;
571 const double DP0 = VP0 + HP0;
572 const double VZP0 = VP0 + K2P0;
573 const double HZP0 = HP0 + K2P0;
574 const double DZP0 = DP0 + K2P0;
575 const double VP2 = VP2a0 * 1.5 - VP2a1 / 2 + 2 * dzvert * K2P2;
576 const double HP2 = HP2a0 * 1.5 - HP2a1 / 2 + 2 * dzhor * K2P2;
577 const double DP2 = VP2 + HP2;
578 const double VZP2 = VP2 + K2P2;
579 const double HZP2 = HP2 + K2P2;
580 const double DZP2 = DP2 + K2P2;
581
582 const double VP0n = VP0na0 * 1.5 - VP0na1 / 2 + 2 * dzvert * K2P0n;
583 const double HP0n = HP0na0 * 1.5 - HP0na1 / 2 + 2 * dzhor * K2P0n;
584 const double DP0n = VP0n + HP0n;
585 const double VZP0n = VP0n + K2P0n;
586 const double HZP0n = HP0n + K2P0n;
587 const double DZP0n = DP0n + K2P0n;
588 const double VP2n = VP2na0 * 1.5 - VP2na1 / 2 + 2 * dzvert * K2P2n;
589 const double HP2n = HP2na0 * 1.5 - HP2na1 / 2 + 2 * dzhor * K2P2n;
590 const double DP2n = VP2n + HP2n;
591 const double VZP2n = VP2n + K2P2n;
592 const double HZP2n = HP2n + K2P2n;
593 const double DZP2n = DP2n + K2P2n;
594
595 // Initial values of update values (Up)
596 double A0a0 = Projptr[0][0][0][1] + ds * K1A0;
597 double A0a1 = Projptr[0][0][0][3] + ds * (K1A0 + K3A0);
598 double A2a0 = Projptr[0][2][0][1] + ds * K1A2;
599 double A2a1 = Projptr[0][2][0][3] + ds * (K1A2 + K3A2);
600
601 double P0na0 = Projptr[1][0][1][1] + ds * K1P0n;
602 double P0na1 = Projptr[1][0][1][3] + ds * (K1P0n + K3P0n);
603 double P2na0 = Projptr[1][2][1][1] + ds * K1P2n;
604 double P2na1 = Projptr[1][2][1][3] + ds * (K1P2n + K3P2n);
605
606 double A0na0 = Projptr[1][0][0][1] + ds * K1A0n;
607 double A0na1 = Projptr[1][0][0][3] + ds * (K1A0n + K3A0n);
608 double A2na0 = Projptr[1][2][0][1] + ds * K1A2n;
609 double A2na1 = Projptr[1][2][0][3] + ds * (K1A2n + K3A2n);
610
611 double P0a0 = Projptr[0][0][1][1] + ds * K1P0;
612 double P0a1 = Projptr[0][0][1][3] + ds * (K1P0 + K3P0);
613 double P2a0 = Projptr[0][2][1][1] + ds * K1P2;
614 double P2a1 = Projptr[0][2][1][3] + ds * (K1P2 + K3P2);
615
616 double UpA0 = 2 * (Projptr[0][0][0][1] + ds * K1A0 + dz * K2A0) - (A0a0 + A0a1) / 2;
617 double UpA2 = 2 * (Projptr[0][2][0][1] + ds * K1A2 + dz * K2A2) - (A2a0 + A2a1) / 2;
618
619 double UpA0n = 2 * (Projptr[1][0][0][1] + ds * K1A0n + dz * K2A0n) - (A0na0 + A0na1) / 2;
620 double UpA2n = 2 * (Projptr[1][2][0][1] + ds * K1A2n + dz * K2A2n) - (A2na0 + A2na1) / 2;
621
622 double UpP0 = 2 * (Projptr[0][0][1][1] + ds * K1P0 + dz * K2P0) - (P0a0 + P0a1) / 2;
623 double UpP2 = 2 * (Projptr[0][2][1][1] + ds * K1P2 + dz * K2P2) - (P2a0 + P2a1) / 2;
624
625 double UpP0n = 2 * (Projptr[1][0][1][1] + ds * K1P0n + dz * K2P0n) - (P0na0 + P0na1) / 2;
626 double UpP2n = 2 * (Projptr[1][2][1][1] + ds * K1P2n + dz * K2P2n) - (P2na0 + P2na1) / 2;
627
628#endif // PIECEWISE_INTERPOLATION
629
630 // some extra start values
631
632 // Find symmetric value in Z by 'mirroring' it around the centre z of the LORs:
633 // Z+Q = 2*centre_of_LOR_in_image_coordinates
634 // Note that we are backprojecting ring0 and ring0+1, so we mirror around ring0+0.5
635 // original Q = (int) (4*ring0+2*delta+2-Z + 0.5);
636 // CL&KT 21/12/99 added axial_pos_to_z_offset and num_planes_per_physical_ring
637 {
638 // first compute it as floating point (although it has to be an int really)
639 const float Qf
640 = (2 * num_planes_per_axial_pos * (ring0 + 0.5) + num_planes_per_physical_ring * delta + 2 * axial_pos_to_z_offset - Z);
641 // now use rounding to be safe
642 Q = (int)floor(Qf + 0.5);
643 assert(fabs(Q - Qf) < 10E-4);
644 }
645
646 dzdiag = dzvert + dzhor;
647 dsdiag = -cphi + sphi;
648
649 /* KT 13/05/98 changed loop condition, originally a combination of
650 while (X>X2||Y<Y2||Z<Z2) {
651 // code which increments Y,Z or decrements X
652 if (X<X2||Y>Y2||Z>Z2)
653 }
654 this had problems for nearly horizontal or vertical lines.
655 For example, while Y==Y2+1, some extra iterations had to be done
656 on X.
657 Now I break out of the while when the voxel goes out of the cylinder,
658 which means I don't have to use X2,Y2,Z2 anymore
659 */
660 do
661 {
662 assert(ds >= 0);
663 assert(ds <= 1);
664 assert(dz >= 0);
665 assert(dz <= ring_unit + epsilon);
666
667 // Update voxel values for this X,Y,Z
668 // For 1 given (X,Y)-position, there are always 2 voxels along the z-axis
669 // in this beam
670 const int Zplus = Z + 1;
671 const int Qmin = Q - 1;
672
673#if PIECEWISE_INTERPOLATION
674 // KT&MJ 07/08/98 new
675
676 // KT 16/06/98 changed check ds!=0 to fabs(ds)>epsilon for better rounding control
677 const bool do_s_symmetry = (s != 0 || fabs(ds) > epsilon);
678 const double twodsdz = 2 * ds * dz;
679 const double twodsdz2 = 2 * ds * (dz + 0.5);
680
681 if (Z >= minplane && Z <= maxplane)
682 {
683 // original image[Z][Y][X]+=UpA0+dsdz*K3A0
684 image[Z][Y][X] += (dz <= 0.25) ? A0a0 : UpA0 + twodsdz * K3A0;
685 image[Z][X][-Y] += (dz <= 0.25) ? A2a0 : UpA2 + twodsdz * K3A2;
686 if (do_s_symmetry)
687 {
688 image[Z][-Y][-X] += (dz <= 0.25) ? P0na0 : UpP0n + twodsdz * K3P0n;
689 image[Z][-X][Y] += (dz <= 0.25) ? P2na0 : UpP2n + twodsdz * K3P2n;
690 }
691 }
692 if (Zplus >= minplane && Zplus <= maxplane)
693 {
694 image[Zplus][Y][X] += (dz >= 0.25) ? A0a1 : UpA0 + twodsdz2 * K3A0 + ZplusKorrA0;
695 image[Zplus][X][-Y] += (dz >= 0.25) ? A2a1 : UpA2 + twodsdz2 * K3A2 + ZplusKorrA2;
696 if (do_s_symmetry)
697 {
698 image[Zplus][-Y][-X] += (dz >= 0.25) ? P0na1 : UpP0n + twodsdz2 * K3P0n + ZplusKorrP0n;
699 image[Zplus][-X][Y] += (dz >= 0.25) ? P2na1 : UpP2n + twodsdz2 * K3P2n + ZplusKorrP2n;
700 }
701 }
702 if (Q >= minplane && Q <= maxplane)
703 {
704 image[Q][Y][X] += (dz <= 0.25) ? A0na0 : UpA0n + twodsdz * K3A0n;
705 image[Q][X][-Y] += (dz <= 0.25) ? A2na0 : UpA2n + twodsdz * K3A2n;
706 if (do_s_symmetry)
707 {
708 image[Q][-Y][-X] += (dz <= 0.25) ? P0a0 : UpP0 + twodsdz * K3P0;
709 image[Q][-X][Y] += (dz <= 0.25) ? P2a0 : UpP2 + twodsdz * K3P2;
710 }
711 }
712 if (Qmin >= minplane && Qmin <= maxplane)
713 {
714 image[Qmin][Y][X] += (dz >= 0.25) ? A0na1 : UpA0n + twodsdz2 * K3A0n + ZplusKorrA0n;
715 image[Qmin][X][-Y] += (dz >= 0.25) ? A2na1 : UpA2n + twodsdz2 * K3A2n + ZplusKorrA2n;
716 if (do_s_symmetry)
717 {
718 image[Qmin][-Y][-X] += (dz >= 0.25) ? P0a1 : UpP0 + twodsdz2 * K3P0 + ZplusKorrP0;
719 image[Qmin][-X][Y] += (dz >= 0.25) ? P2a1 : UpP2 + twodsdz2 * K3P2 + ZplusKorrP2;
720 }
721 }
722#else // !PIECEWISE_INTERPOLATION
723# ifdef ALTERNATIVE
724 // This code and the one after #else are equivalent. However, this version is
725 // shorter, while the other version looks 'more optimal'.
726 // TODO check which is faster.
727 // KT 16/06/98 changed check ds!=0 to fabs(ds)>epsilon for better rounding control
728 const bool do_s_symmetry = (s != 0 || fabs(ds) > epsilon);
729 const double dsdz = ds * dz;
730 const double dsdz2 = ds * (dz + ring_unit);
731
732 if (Z >= minplane && Z <= maxplane)
733 {
734 image[Z][Y][X] += UpA0 + dsdz * K3A0;
735 image[Z][X][-Y] += UpA2 + dsdz * K3A2;
736 if (do_s_symmetry)
737 {
738 image[Z][-Y][-X] += UpP0n + dsdz * K3P0n;
739 image[Z][-X][Y] += UpP2n + dsdz * K3P2n;
740 }
741 }
742 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
743 // as there is only one voxel in the beam in slice unit
744 if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5)
745 {
746 image[Zplus][Y][X] += UpA0 + dsdz2 * K3A0 + ZplusKorrA0;
747 image[Zplus][X][-Y] += UpA2 + dsdz2 * K3A2 + ZplusKorrA2;
748 if (do_s_symmetry)
749 {
750 image[Zplus][-Y][-X] += UpP0n + dsdz2 * K3P0n + ZplusKorrP0n;
751 image[Zplus][-X][Y] += UpP2n + dsdz2 * K3P2n + ZplusKorrP2n;
752 }
753 }
754 if (Q >= minplane && Q <= maxplane)
755 {
756 image[Q][Y][X] += UpA0n + dsdz * K3A0n;
757 image[Q][X][-Y] += UpA2n + dsdz * K3A2n;
758 if (do_s_symmetry)
759 {
760 image[Q][-Y][-X] += UpP0 + dsdz * K3P0;
761 image[Q][-X][Y] += UpP2 + dsdz * K3P2;
762 }
763 }
764 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
765 // as there is only one voxel in the beam in slice unit
766 if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5)
767 {
768 image[Qmin][Y][X] += UpA0n + dsdz2 * K3A0n + ZplusKorrA0n;
769 image[Qmin][X][-Y] += UpA2n + dsdz2 * K3A2n + ZplusKorrA2n;
770 if (do_s_symmetry)
771 {
772 image[Qmin][-Y][-X] += UpP0 + dsdz2 * K3P0 + ZplusKorrP0;
773 image[Qmin][-X][Y] += UpP2 + dsdz2 * K3P2 + ZplusKorrP2;
774 }
775 }
776# else // ALTERNATIVE
777 double TMP1, TMP2;
778
779 // if(Z == maxplane || Q == maxplane || Zplus == maxplane || Qmin == maxplane)
780 // cout << " " << ring0 ;
781
782 TMP1 = ds * K3A0;
783 TMP2 = UpA0 + dz * TMP1;
784 if (Z >= minplane && Z <= maxplane)
785 image[Z][Y][X] += TMP2;
786 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
787 // as there is only one voxel in the beam in slice unit
788 if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5)
789 image[Zplus][Y][X] += TMP2 + ring_unit * TMP1 + ZplusKorrA0;
790 TMP1 = ds * K3A2;
791 TMP2 = UpA2 + dz * TMP1;
792 if (Z >= minplane && Z <= maxplane)
793 image[Z][X][-Y] += TMP2;
794 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
795 // as there is only one voxel in the beam in slice unit
796 if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5)
797 image[Zplus][X][-Y] += TMP2 + ring_unit * TMP1 + ZplusKorrA2;
798
799 TMP1 = ds * K3A0n;
800 TMP2 = UpA0n + dz * TMP1;
801 if (Q >= minplane && Q <= maxplane)
802 image[Q][Y][X] += TMP2;
803 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
804 // as there is only one voxel in the beam in slice unit
805 if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5)
806 image[Qmin][Y][X] += TMP2 + ring_unit * TMP1 + ZplusKorrA0n;
807 TMP1 = ds * K3A2n;
808 TMP2 = UpA2n + dz * TMP1;
809 if (Q >= minplane && Q <= maxplane)
810 image[Q][X][-Y] += TMP2;
811 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
812 // as there is only one voxel in the beam in slice unit
813 if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5)
814 image[Qmin][X][-Y] += TMP2 + ring_unit * TMP1 + ZplusKorrA2n;
815
816 // KT 14/05/98 changed X!=-Y to s!=0 || ds!=0 to make it work for view != view45
817 // KT 16/06/98 changed check ds!=0 to fabs(ds)>epsilon for better rounding control
818 if (s != 0 || fabs(ds) > epsilon)
819 {
820 TMP1 = ds * K3P0;
821 TMP2 = UpP0 + dz * TMP1;
822 if (Q >= minplane && Q <= maxplane)
823 image[Q][-Y][-X] += TMP2;
824 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
825 // as there is only one voxel in the beam in slice unit
826 if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5)
827 image[Qmin][-Y][-X] += TMP2 + ring_unit * TMP1 + ZplusKorrP0;
828 TMP1 = ds * K3P2;
829 TMP2 = UpP2 + dz * TMP1;
830 if (Q >= minplane && Q <= maxplane)
831 image[Q][-X][Y] += TMP2;
832 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
833 // as there is only one voxel in the beam in slice unit
834 if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5)
835 image[Qmin][-X][Y] += TMP2 + ring_unit * TMP1 + ZplusKorrP2;
836
837 TMP1 = ds * K3P0n;
838 TMP2 = UpP0n + dz * TMP1;
839 if (Z >= minplane && Z <= maxplane)
840 image[Z][-Y][-X] += TMP2;
841 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
842 // as there is only one voxel in the beam in slice unit
843 if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5)
844 image[Zplus][-Y][-X] += TMP2 + ring_unit * TMP1 + ZplusKorrP0n;
845 TMP1 = ds * K3P2n;
846 TMP2 = UpP2n + dz * TMP1;
847 if (Z >= minplane && Z <= maxplane)
848 image[Z][-X][Y] += TMP2;
849 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
850 // as there is only one voxel in the beam in slice unit
851 if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5)
852 image[Zplus][-X][Y] += TMP2 + ring_unit * TMP1 + ZplusKorrP2n;
853 }
854# endif // ALTERNATIVE
855#endif // PIECEWISE_INTERPOLATION
856
857 // Search for next pixel in the beam
858
859 if (ds >= cphi)
860 {
861 /* horizontal*/
862 X -= 1;
863 ds -= cphi;
864 dz += dzhor;
865 if (dz < epsilon)
866 { /* increment Z */
867 Z++;
868 Q--;
869 dz += ring_unit;
870 UpA0 += HZA0;
871 UpA2 += HZA2;
872 UpA0n += HZA0n;
873 UpA2n += HZA2n;
874 UpP0 += HZP0;
875 UpP2 += HZP2;
876 UpP0n += HZP0n;
877 UpP2n += HZP2n;
878#ifdef MOREZ
879 while (dz < epsilon)
880 {
881 Z++;
882 Q--;
883 dz += ring_unit;
884 UpA0 += HZA0 - HA0;
885 UpA2 += HZA2 - HA2;
886 UpA0n += HZA0n - HA0n;
887 UpA2n += HZA2n - HA2n;
888 UpP0 += HZP0 - HP0;
889 UpP2 += HZP2 - HP2;
890 UpP0n += HZP0n - HP0n;
891 UpP2n += HZP2n - HP2n;
892 }
893#endif
894 }
895
896 else
897 { /* Z does not change */
898 UpA0 += HA0;
899 UpA2 += HA2;
900 UpA0n += HA0n;
901 UpA2n += HA2n;
902 UpP0 += HP0;
903 UpP2 += HP2;
904 UpP0n += HP0n;
905 UpP2n += HP2n;
906 }
907#if PIECEWISE_INTERPOLATION
908 A0a0 += HA0a0;
909 A2a0 += HA2a0;
910 A0na0 += HA0na0;
911 A2na0 += HA2na0;
912 P0a0 += HP0a0;
913 P2a0 += HP2a0;
914 P0na0 += HP0na0;
915 P2na0 += HP2na0;
916
917 A0a1 += HA0a1;
918 A2a1 += HA2a1;
919 A0na1 += HA0na1;
920 A2na1 += HA2na1;
921 P0a1 += HP0a1;
922 P2a1 += HP2a1;
923 P0na1 += HP0na1;
924 P2na1 += HP2na1;
925#endif // PIECEWISE_INTERPOLATION
926 }
927 // KT 14/05/98 use < instead of <= (see formula 6.17 in Egger's thesis)
928 else if (ds < 1 - sphi)
929 {
930 /* vertical*/
931 Y += 1;
932 ds += sphi;
933 dz += dzvert;
934 if (dz < epsilon)
935 { /* increment Z */
936 Z++;
937 Q--;
938 dz += ring_unit;
939 UpA0 += VZA0;
940 UpA2 += VZA2;
941 UpA0n += VZA0n;
942 UpA2n += VZA2n;
943 UpP0 += VZP0;
944 UpP2 += VZP2;
945 UpP0n += VZP0n;
946 UpP2n += VZP2n;
947
948#ifdef MOREZ
949 while (dz < epsilon)
950 {
951 Z++;
952 Q--;
953 dz += ring_unit;
954 UpA0 += VZA0 - VA0;
955 UpA2 += VZA2 - VA2;
956 UpA0n += VZA0n - VA0n;
957 UpA2n += VZA2n - VA2n;
958 UpP0 += VZP0 - VP0;
959 UpP2 += VZP2 - VP2;
960 UpP0n += VZP0n - VP0n;
961 UpP2n += VZP2n - VP2n;
962 }
963#endif
964 }
965 else
966 { /* Z does not change */
967 UpA0 += VA0;
968 UpA2 += VA2;
969 UpA0n += VA0n;
970 UpA2n += VA2n;
971 UpP0 += VP0;
972 UpP2 += VP2;
973 UpP0n += VP0n;
974 UpP2n += VP2n;
975 }
976#if PIECEWISE_INTERPOLATION
977 A0a0 += VA0a0;
978 A2a0 += VA2a0;
979 A0na0 += VA0na0;
980 A2na0 += VA2na0;
981 P0a0 += VP0a0;
982 P2a0 += VP2a0;
983 P0na0 += VP0na0;
984 P2na0 += VP2na0;
985
986 A0a1 += VA0a1;
987 A2a1 += VA2a1;
988 A0na1 += VA0na1;
989 A2na1 += VA2na1;
990 P0a1 += VP0a1;
991 P2a1 += VP2a1;
992 P0na1 += VP0na1;
993 P2na1 += VP2na1;
994#endif // PIECEWISE_INTERPOLATION
995 }
996 else
997 {
998 /* diagonal*/
999 X -= 1;
1000 Y += 1;
1001 ds += dsdiag;
1002 dz += dzdiag;
1003 if (dz < epsilon)
1004 { /* increment Z */
1005 Z++;
1006 Q--;
1007 dz += ring_unit;
1008 UpA0 += DZA0;
1009 UpA2 += DZA2;
1010 UpA0n += DZA0n;
1011 UpA2n += DZA2n;
1012 UpP0 += DZP0;
1013 UpP2 += DZP2;
1014 UpP0n += DZP0n;
1015 UpP2n += DZP2n;
1016#ifdef MOREZ
1017 while (dz < epsilon)
1018 {
1019 Z++;
1020 Q--;
1021 dz += ring_unit;
1022 UpA0 += DZA0 - DA0;
1023 UpA2 += DZA2 - DA2;
1024 UpA0n += DZA0n - DA0n;
1025 UpA2n += DZA2n - DA2n;
1026 UpP0 += DZP0 - DP0;
1027 UpP2 += DZP2 - DP2;
1028 UpP0n += DZP0n - DP0n;
1029 UpP2n += DZP2n - DP2n;
1030 }
1031#endif
1032 }
1033
1034 else
1035 { /* Z does not change */
1036 UpA0 += DA0;
1037 UpA2 += DA2;
1038 UpA0n += DA0n;
1039 UpA2n += DA2n;
1040 UpP0 += DP0;
1041 UpP2 += DP2;
1042 UpP0n += DP0n;
1043 UpP2n += DP2n;
1044 }
1045#if PIECEWISE_INTERPOLATION
1046 A0a0 += DA0a0;
1047 A2a0 += DA2a0;
1048 A0na0 += DA0na0;
1049 A2na0 += DA2na0;
1050 P0a0 += DP0a0;
1051 P2a0 += DP2a0;
1052 P0na0 += DP0na0;
1053 P2na0 += DP2na0;
1054
1055 A0a1 += DA0a1;
1056 A2a1 += DA2a1;
1057 A0na1 += DA0na1;
1058 A2na1 += DA2na1;
1059 P0a1 += DP0a1;
1060 P2a1 += DP2a1;
1061 P0na1 += DP0na1;
1062 P2na1 += DP2na1;
1063#endif // PIECEWISE_INTERPOLATION
1064 }
1065 check_values(
1066 proj_data_info_sptr, delta, cphi, sphi, s, ring0, X, Y, Z, ds, dz, num_planes_per_axial_pos, axial_pos_to_z_offset);
1067 } while ((X * X + Y * Y <= image_rad * image_rad) && (Z <= maxplane || Q >= minplane));
1068}
1069
1070/*****************************************************************************
1071
1072 backproj3D_Cho_view_viewplus90_180minview_90minview backprojects 8 beams
1073 related by symmetry (see bckproj.h)
1074
1075 The structure of this function is essentially the same as the previous one.
1076 Only we have more variables because we are handling 8 viewgrams here.
1077 *****************************************************************************/
1078
1079// KT 22/05/98 new, but extracted from backproj3D_ChoViews
1080// (which used to be called Backproj_Cho_Symsphitheta_P)
1081
1082void
1083BackProjectorByBinUsingInterpolation::
1084#if PIECEWISE_INTERPOLATION
1085 piecewise_linear_interpolation_backproj3D_Cho_view_viewplus90_180minview_90minview
1086#else
1087 linear_interpolation_backproj3D_Cho_view_viewplus90_180minview_90minview
1088#endif
1089 (Array<4, float> const& Projptr,
1090 VoxelsOnCartesianGrid<float>& image,
1091 const shared_ptr<const ProjDataInfoCylindricalArcCorr> proj_data_info_sptr,
1092 float delta,
1093 const double cphi,
1094 const double sphi,
1095 int s,
1096 int ring0,
1097 const int num_planes_per_axial_pos,
1098 const float axial_pos_to_z_offset)
1099{
1100 // KT 04/05/2000 new check
1101#if PIECEWISE_INTERPOLATION
1102 if (num_planes_per_axial_pos == 1 && delta != 0)
1103 error("This version of the backprojector cannot be used for span>1. \
1104Recompile %s with PIECEWISE_INTERPOLATION=0",
1105 __FILE__);
1106#else
1107# ifdef ALTERNATIVE
1108 // TODO
1109 if (num_planes_per_axial_pos == 1 && delta != 0)
1110 error("This version of the backprojector cannot be used for span>1. \
1111Recompile %s with ALTERNATIVE not #defined",
1112 __FILE__);
1113# endif
1114#endif
1115
1116#ifndef MOREZ
1117 // KT 14/04/2000 new check
1118 /* Check if delta is not too large. If the condition below is violated,
1119 z might have to be incremented more than once to remain in the beam.
1120 To do this, the code would have to be modified with while() instead of if().
1121 As this will slow it down, we just abort at the moment.
1122 */
1123
1124 if (delta * proj_data_info_sptr_info_cyl_ptr->get_tangential_sampling() / proj_data_info_sptr_info_cyl_ptr->get_ring_radius()
1125 > 1)
1126 {
1127 error("This backprojector cannot handle such oblique segments: delta = %g. Sorry.\n", delta);
1128 }
1129#endif
1130
1131 // conditions on searching flow
1132 assert(cphi >= 0 - .001);
1133 assert(sphi >= 0 - .001);
1134 assert(cphi + sphi >= 1 - .001);
1135
1136 const float ring_unit = 1. / num_planes_per_axial_pos;
1137 // CL&KT 21/12/99 new
1138 // in our current coordinate system, the following constant is always 2
1139 const int num_planes_per_physical_ring = 2;
1140 assert(fabs(image.get_voxel_size().z() * num_planes_per_physical_ring / proj_data_info_sptr->get_ring_spacing() - 1) < 10E-4);
1141
1142 double dzvert, dzhor, ds;
1143 double dsdiag, dzdiag, dz;
1144 int X, Y, Z, Q;
1145
1146 /* FOV radius in voxel units */
1147 // KT 20/06/2001 change calculation of FOV such that even sized image will work
1148 const float fovrad_in_mm = min((min(image.get_max_x(), -image.get_min_x())) * image.get_voxel_size().x(),
1149 (min(image.get_max_y(), -image.get_min_y())) * image.get_voxel_size().y());
1150 const float image_rad = fovrad_in_mm / image.get_voxel_size().x() - 2;
1151 // const int image_rad = (int)((image.get_x_size()-1)/2);
1152 // KT 20/06/2001 allow min_z!=0 in all comparisons below
1153 const int minplane = image.get_min_z();
1154 const int maxplane = image.get_max_z();
1155
1156 if (find_start_values(proj_data_info_sptr,
1157 delta,
1158 cphi,
1159 sphi,
1160 s,
1161 ring0,
1162 image_rad,
1163 image.get_voxel_size().z(),
1164 X,
1165 Y,
1166 Z,
1167 ds,
1168 dz,
1169 dzhor,
1170 dzvert,
1171 num_planes_per_axial_pos,
1172 axial_pos_to_z_offset)
1173 == Succeeded::no)
1174 {
1175 // no voxels in the beam
1176 return;
1177 }
1178
1179 // K1, K2, K3 invariants
1180
1181 const double K1A0 = Projptr[0][0][0][2] - Projptr[0][0][0][1];
1182 const double K2A0 = Projptr[0][0][0][3] - Projptr[0][0][0][1];
1183 const double K3A0 = Projptr[0][0][0][4] - Projptr[0][0][0][2] - K2A0;
1184 const double K1A1 = Projptr[0][1][0][2] - Projptr[0][1][0][1];
1185 const double K2A1 = Projptr[0][1][0][3] - Projptr[0][1][0][1];
1186 const double K3A1 = Projptr[0][1][0][4] - Projptr[0][1][0][2] - K2A1;
1187 const double K1A2 = Projptr[0][2][0][2] - Projptr[0][2][0][1];
1188 const double K2A2 = Projptr[0][2][0][3] - Projptr[0][2][0][1];
1189 const double K3A2 = Projptr[0][2][0][4] - Projptr[0][2][0][2] - K2A2;
1190 const double K1A3 = Projptr[0][3][0][2] - Projptr[0][3][0][1];
1191 const double K2A3 = Projptr[0][3][0][3] - Projptr[0][3][0][1];
1192 const double K3A3 = Projptr[0][3][0][4] - Projptr[0][3][0][2] - K2A3;
1193
1194 const double K1A0n = Projptr[1][0][0][2] - Projptr[1][0][0][1];
1195 const double K2A0n = Projptr[1][0][0][3] - Projptr[1][0][0][1];
1196 const double K3A0n = Projptr[1][0][0][4] - Projptr[1][0][0][2] - K2A0n;
1197 const double K1A1n = Projptr[1][1][0][2] - Projptr[1][1][0][1];
1198 const double K2A1n = Projptr[1][1][0][3] - Projptr[1][1][0][1];
1199 const double K3A1n = Projptr[1][1][0][4] - Projptr[1][1][0][2] - K2A1n;
1200 const double K1A2n = Projptr[1][2][0][2] - Projptr[1][2][0][1];
1201 const double K2A2n = Projptr[1][2][0][3] - Projptr[1][2][0][1];
1202 const double K3A2n = Projptr[1][2][0][4] - Projptr[1][2][0][2] - K2A2n;
1203 const double K1A3n = Projptr[1][3][0][2] - Projptr[1][3][0][1];
1204 const double K2A3n = Projptr[1][3][0][3] - Projptr[1][3][0][1];
1205 const double K3A3n = Projptr[1][3][0][4] - Projptr[1][3][0][2] - K2A3n;
1206
1207 const double K1P0 = Projptr[0][0][1][2] - Projptr[0][0][1][1];
1208 const double K2P0 = Projptr[0][0][1][3] - Projptr[0][0][1][1];
1209 const double K3P0 = Projptr[0][0][1][4] - Projptr[0][0][1][2] - K2P0;
1210 const double K1P1 = Projptr[0][1][1][2] - Projptr[0][1][1][1];
1211 const double K2P1 = Projptr[0][1][1][3] - Projptr[0][1][1][1];
1212 const double K3P1 = Projptr[0][1][1][4] - Projptr[0][1][1][2] - K2P1;
1213 const double K1P2 = Projptr[0][2][1][2] - Projptr[0][2][1][1];
1214 const double K2P2 = Projptr[0][2][1][3] - Projptr[0][2][1][1];
1215 const double K3P2 = Projptr[0][2][1][4] - Projptr[0][2][1][2] - K2P2;
1216 const double K1P3 = Projptr[0][3][1][2] - Projptr[0][3][1][1];
1217 const double K2P3 = Projptr[0][3][1][3] - Projptr[0][3][1][1];
1218 const double K3P3 = Projptr[0][3][1][4] - Projptr[0][3][1][2] - K2P3;
1219
1220 const double K1P0n = Projptr[1][0][1][2] - Projptr[1][0][1][1];
1221 const double K2P0n = Projptr[1][0][1][3] - Projptr[1][0][1][1];
1222 const double K3P0n = Projptr[1][0][1][4] - Projptr[1][0][1][2] - K2P0n;
1223 const double K1P1n = Projptr[1][1][1][2] - Projptr[1][1][1][1];
1224 const double K2P1n = Projptr[1][1][1][3] - Projptr[1][1][1][1];
1225 const double K3P1n = Projptr[1][1][1][4] - Projptr[1][1][1][2] - K2P1n;
1226 const double K1P2n = Projptr[1][2][1][2] - Projptr[1][2][1][1];
1227 const double K2P2n = Projptr[1][2][1][3] - Projptr[1][2][1][1];
1228 const double K3P2n = Projptr[1][2][1][4] - Projptr[1][2][1][2] - K2P2n;
1229 const double K1P3n = Projptr[1][3][1][2] - Projptr[1][3][1][1];
1230 const double K2P3n = Projptr[1][3][1][3] - Projptr[1][3][1][1];
1231 const double K3P3n = Projptr[1][3][1][4] - Projptr[1][3][1][2] - K2P3n;
1232
1233#if !PIECEWISE_INTERPOLATION
1234
1235 const double ZplusKorrA0 = ring_unit * K2A0;
1236 const double ZplusKorrA1 = ring_unit * K2A1;
1237 const double ZplusKorrA2 = ring_unit * K2A2;
1238 const double ZplusKorrA3 = ring_unit * K2A3;
1239
1240 const double ZplusKorrA0n = ring_unit * K2A0n;
1241 const double ZplusKorrA1n = ring_unit * K2A1n;
1242 const double ZplusKorrA2n = ring_unit * K2A2n;
1243 const double ZplusKorrA3n = ring_unit * K2A3n;
1244
1245 const double ZplusKorrP0 = ring_unit * K2P0;
1246 const double ZplusKorrP1 = ring_unit * K2P1;
1247 const double ZplusKorrP2 = ring_unit * K2P2;
1248 const double ZplusKorrP3 = ring_unit * K2P3;
1249
1250 const double ZplusKorrP0n = ring_unit * K2P0n;
1251 const double ZplusKorrP1n = ring_unit * K2P1n;
1252 const double ZplusKorrP2n = ring_unit * K2P2n;
1253 const double ZplusKorrP3n = ring_unit * K2P3n;
1254
1255 // V, H, D invariants
1256
1257 const double VA0 = dzvert * K2A0 + sphi * K1A0;
1258 const double HA0 = dzhor * K2A0 - cphi * K1A0;
1259 const double DA0 = VA0 + HA0;
1260 const double VZA0 = VA0 + ring_unit * K2A0;
1261 const double HZA0 = HA0 + ring_unit * K2A0;
1262 const double DZA0 = DA0 + ring_unit * K2A0;
1263 const double VA1 = dzvert * K2A1 + sphi * K1A1;
1264 const double HA1 = dzhor * K2A1 - cphi * K1A1;
1265 const double DA1 = VA1 + HA1;
1266 const double VZA1 = VA1 + ring_unit * K2A1;
1267 const double HZA1 = HA1 + ring_unit * K2A1;
1268 const double DZA1 = DA1 + ring_unit * K2A1;
1269 const double VA2 = dzvert * K2A2 + sphi * K1A2;
1270 const double HA2 = dzhor * K2A2 - cphi * K1A2;
1271 const double DA2 = VA2 + HA2;
1272 const double VZA2 = VA2 + ring_unit * K2A2;
1273 const double HZA2 = HA2 + ring_unit * K2A2;
1274 const double DZA2 = DA2 + ring_unit * K2A2;
1275 const double VA3 = dzvert * K2A3 + sphi * K1A3;
1276 const double HA3 = dzhor * K2A3 - cphi * K1A3;
1277 const double DA3 = VA3 + HA3;
1278 const double VZA3 = VA3 + ring_unit * K2A3;
1279 const double HZA3 = HA3 + ring_unit * K2A3;
1280 const double DZA3 = DA3 + ring_unit * K2A3;
1281
1282 const double VA0n = dzvert * K2A0n + sphi * K1A0n;
1283 const double HA0n = dzhor * K2A0n - cphi * K1A0n;
1284 const double DA0n = VA0n + HA0n;
1285 const double VZA0n = VA0n + ring_unit * K2A0n;
1286 const double HZA0n = HA0n + ring_unit * K2A0n;
1287 const double DZA0n = DA0n + ring_unit * K2A0n;
1288 const double VA1n = dzvert * K2A1n + sphi * K1A1n;
1289 const double HA1n = dzhor * K2A1n - cphi * K1A1n;
1290 const double DA1n = VA1n + HA1n;
1291 const double VZA1n = VA1n + ring_unit * K2A1n;
1292 const double HZA1n = HA1n + ring_unit * K2A1n;
1293 const double DZA1n = DA1n + ring_unit * K2A1n;
1294 const double VA2n = dzvert * K2A2n + sphi * K1A2n;
1295 const double HA2n = dzhor * K2A2n - cphi * K1A2n;
1296 const double DA2n = VA2n + HA2n;
1297 const double VZA2n = VA2n + ring_unit * K2A2n;
1298 const double HZA2n = HA2n + ring_unit * K2A2n;
1299 const double DZA2n = DA2n + ring_unit * K2A2n;
1300 const double VA3n = dzvert * K2A3n + sphi * K1A3n;
1301 const double HA3n = dzhor * K2A3n - cphi * K1A3n;
1302 const double DA3n = VA3n + HA3n;
1303 const double VZA3n = VA3n + ring_unit * K2A3n;
1304 const double HZA3n = HA3n + ring_unit * K2A3n;
1305 const double DZA3n = DA3n + ring_unit * K2A3n;
1306
1307 const double VP0 = dzvert * K2P0 + sphi * K1P0;
1308 const double HP0 = dzhor * K2P0 - cphi * K1P0;
1309 const double DP0 = VP0 + HP0;
1310 const double VZP0 = VP0 + ring_unit * K2P0;
1311 const double HZP0 = HP0 + ring_unit * K2P0;
1312 const double DZP0 = DP0 + ring_unit * K2P0;
1313 const double VP1 = dzvert * K2P1 + sphi * K1P1;
1314 const double HP1 = dzhor * K2P1 - cphi * K1P1;
1315 const double DP1 = VP1 + HP1;
1316 const double VZP1 = VP1 + ring_unit * K2P1;
1317 const double HZP1 = HP1 + ring_unit * K2P1;
1318 const double DZP1 = DP1 + ring_unit * K2P1;
1319 const double VP2 = dzvert * K2P2 + sphi * K1P2;
1320 const double HP2 = dzhor * K2P2 - cphi * K1P2;
1321 const double DP2 = VP2 + HP2;
1322 const double VZP2 = VP2 + ring_unit * K2P2;
1323 const double HZP2 = HP2 + ring_unit * K2P2;
1324 const double DZP2 = DP2 + ring_unit * K2P2;
1325 const double VP3 = dzvert * K2P3 + sphi * K1P3;
1326 const double HP3 = dzhor * K2P3 - cphi * K1P3;
1327 const double DP3 = VP3 + HP3;
1328 const double VZP3 = VP3 + ring_unit * K2P3;
1329 const double HZP3 = HP3 + ring_unit * K2P3;
1330 const double DZP3 = DP3 + ring_unit * K2P3;
1331
1332 const double VP0n = dzvert * K2P0n + sphi * K1P0n;
1333 const double HP0n = dzhor * K2P0n - cphi * K1P0n;
1334 const double DP0n = VP0n + HP0n;
1335 const double VZP0n = VP0n + ring_unit * K2P0n;
1336 const double HZP0n = HP0n + ring_unit * K2P0n;
1337 const double DZP0n = DP0n + ring_unit * K2P0n;
1338 const double VP1n = dzvert * K2P1n + sphi * K1P1n;
1339 const double HP1n = dzhor * K2P1n - cphi * K1P1n;
1340 const double DP1n = VP1n + HP1n;
1341 const double VZP1n = VP1n + ring_unit * K2P1n;
1342 const double HZP1n = HP1n + ring_unit * K2P1n;
1343 const double DZP1n = DP1n + ring_unit * K2P1n;
1344 const double VP2n = dzvert * K2P2n + sphi * K1P2n;
1345 const double HP2n = dzhor * K2P2n - cphi * K1P2n;
1346 const double DP2n = VP2n + HP2n;
1347 const double VZP2n = VP2n + ring_unit * K2P2n;
1348 const double HZP2n = HP2n + ring_unit * K2P2n;
1349 const double DZP2n = DP2n + ring_unit * K2P2n;
1350 const double VP3n = dzvert * K2P3n + sphi * K1P3n;
1351 const double HP3n = dzhor * K2P3n - cphi * K1P3n;
1352 const double DP3n = VP3n + HP3n;
1353 const double VZP3n = VP3n + ring_unit * K2P3n;
1354 const double HZP3n = HP3n + ring_unit * K2P3n;
1355 const double DZP3n = DP3n + ring_unit * K2P3n;
1356
1357 // Initial values of update values (Up)
1358
1359 double UpA0 = Projptr[0][0][0][1] + ds * K1A0 + dz * K2A0;
1360 double UpA1 = Projptr[0][1][0][1] + ds * K1A1 + dz * K2A1;
1361 double UpA2 = Projptr[0][2][0][1] + ds * K1A2 + dz * K2A2;
1362 double UpA3 = Projptr[0][3][0][1] + ds * K1A3 + dz * K2A3;
1363
1364 double UpA0n = Projptr[1][0][0][1] + ds * K1A0n + dz * K2A0n;
1365 double UpA1n = Projptr[1][1][0][1] + ds * K1A1n + dz * K2A1n;
1366 double UpA2n = Projptr[1][2][0][1] + ds * K1A2n + dz * K2A2n;
1367 double UpA3n = Projptr[1][3][0][1] + ds * K1A3n + dz * K2A3n;
1368
1369 double UpP0 = Projptr[0][0][1][1] + ds * K1P0 + dz * K2P0;
1370 double UpP1 = Projptr[0][1][1][1] + ds * K1P1 + dz * K2P1;
1371 double UpP2 = Projptr[0][2][1][1] + ds * K1P2 + dz * K2P2;
1372 double UpP3 = Projptr[0][3][1][1] + ds * K1P3 + dz * K2P3;
1373
1374 double UpP0n = Projptr[1][0][1][1] + ds * K1P0n + dz * K2P0n;
1375 double UpP1n = Projptr[1][1][1][1] + ds * K1P1n + dz * K2P1n;
1376 double UpP2n = Projptr[1][2][1][1] + ds * K1P2n + dz * K2P2n;
1377 double UpP3n = Projptr[1][3][1][1] + ds * K1P3n + dz * K2P3n;
1378
1379#else // PIECEWISE_INTERPOLATION
1380
1381 const double ZplusKorrA0 = K2A0;
1382 const double ZplusKorrA1 = K2A1;
1383 const double ZplusKorrA2 = K2A2;
1384 const double ZplusKorrA3 = K2A3;
1385
1386 const double ZplusKorrA0n = K2A0n;
1387 const double ZplusKorrA1n = K2A1n;
1388 const double ZplusKorrA2n = K2A2n;
1389 const double ZplusKorrA3n = K2A3n;
1390
1391 const double ZplusKorrP0 = K2P0;
1392 const double ZplusKorrP1 = K2P1;
1393 const double ZplusKorrP2 = K2P2;
1394 const double ZplusKorrP3 = K2P3;
1395
1396 const double ZplusKorrP0n = K2P0n;
1397 const double ZplusKorrP1n = K2P1n;
1398 const double ZplusKorrP2n = K2P2n;
1399 const double ZplusKorrP3n = K2P3n;
1400
1401 // V, H, D invariants
1402
1403 const double VA0a0 = +sphi * K1A0;
1404 const double HA0a0 = -cphi * K1A0;
1405 const double DA0a0 = VA0a0 + HA0a0;
1406 const double VA1a0 = +sphi * K1A1;
1407 const double HA1a0 = -cphi * K1A1;
1408 const double DA1a0 = VA1a0 + HA1a0;
1409 const double VA2a0 = +sphi * K1A2;
1410 const double HA2a0 = -cphi * K1A2;
1411 const double DA2a0 = VA2a0 + HA2a0;
1412 const double VA3a0 = +sphi * K1A3;
1413 const double HA3a0 = -cphi * K1A3;
1414 const double DA3a0 = VA3a0 + HA3a0;
1415
1416 const double VA0na0 = +sphi * K1A0n;
1417 const double HA0na0 = -cphi * K1A0n;
1418 const double DA0na0 = VA0na0 + HA0na0;
1419 const double VA1na0 = +sphi * K1A1n;
1420 const double HA1na0 = -cphi * K1A1n;
1421 const double DA1na0 = VA1na0 + HA1na0;
1422 const double VA2na0 = +sphi * K1A2n;
1423 const double HA2na0 = -cphi * K1A2n;
1424 const double DA2na0 = VA2na0 + HA2na0;
1425 const double VA3na0 = +sphi * K1A3n;
1426 const double HA3na0 = -cphi * K1A3n;
1427 const double DA3na0 = VA3na0 + HA3na0;
1428
1429 const double VP0a0 = +sphi * K1P0;
1430 const double HP0a0 = -cphi * K1P0;
1431 const double DP0a0 = VP0a0 + HP0a0;
1432 const double VP1a0 = +sphi * K1P1;
1433 const double HP1a0 = -cphi * K1P1;
1434 const double DP1a0 = VP1a0 + HP1a0;
1435 const double VP2a0 = +sphi * K1P2;
1436 const double HP2a0 = -cphi * K1P2;
1437 const double DP2a0 = VP2a0 + HP2a0;
1438 const double VP3a0 = +sphi * K1P3;
1439 const double HP3a0 = -cphi * K1P3;
1440 const double DP3a0 = VP3a0 + HP3a0;
1441
1442 const double VP0na0 = +sphi * K1P0n;
1443 const double HP0na0 = -cphi * K1P0n;
1444 const double DP0na0 = VP0na0 + HP0na0;
1445 const double VP1na0 = +sphi * K1P1n;
1446 const double HP1na0 = -cphi * K1P1n;
1447 const double DP1na0 = VP1na0 + HP1na0;
1448 const double VP2na0 = +sphi * K1P2n;
1449 const double HP2na0 = -cphi * K1P2n;
1450 const double DP2na0 = VP2na0 + HP2na0;
1451 const double VP3na0 = +sphi * K1P3n;
1452 const double HP3na0 = -cphi * K1P3n;
1453 const double DP3na0 = VP3na0 + HP3na0;
1454
1455 const double VA0a1 = +sphi * (K1A0 + K3A0);
1456 const double HA0a1 = -cphi * (K1A0 + K3A0);
1457 const double DA0a1 = VA0a1 + HA0a1;
1458 const double VA1a1 = +sphi * (K1A1 + K3A1);
1459 const double HA1a1 = -cphi * (K1A1 + K3A1);
1460 const double DA1a1 = VA1a1 + HA1a1;
1461 const double VA2a1 = +sphi * (K1A2 + K3A2);
1462 const double HA2a1 = -cphi * (K1A2 + K3A2);
1463 const double DA2a1 = VA2a1 + HA2a1;
1464 const double VA3a1 = +sphi * (K1A3 + K3A3);
1465 const double HA3a1 = -cphi * (K1A3 + K3A3);
1466 const double DA3a1 = VA3a1 + HA3a1;
1467
1468 const double VA0na1 = +sphi * (K1A0n + K3A0n);
1469 const double HA0na1 = -cphi * (K1A0n + K3A0n);
1470 const double DA0na1 = VA0na1 + HA0na1;
1471 const double VA1na1 = +sphi * (K1A1n + K3A1n);
1472 const double HA1na1 = -cphi * (K1A1n + K3A1n);
1473 const double DA1na1 = VA1na1 + HA1na1;
1474 const double VA2na1 = +sphi * (K1A2n + K3A2n);
1475 const double HA2na1 = -cphi * (K1A2n + K3A2n);
1476 const double DA2na1 = VA2na1 + HA2na1;
1477 const double VA3na1 = +sphi * (K1A3n + K3A3n);
1478 const double HA3na1 = -cphi * (K1A3n + K3A3n);
1479 const double DA3na1 = VA3na1 + HA3na1;
1480
1481 const double VP0a1 = +sphi * (K1P0 + K3P0);
1482 const double HP0a1 = -cphi * (K1P0 + K3P0);
1483 const double DP0a1 = VP0a1 + HP0a1;
1484 const double VP1a1 = +sphi * (K1P1 + K3P1);
1485 const double HP1a1 = -cphi * (K1P1 + K3P1);
1486 const double DP1a1 = VP1a1 + HP1a1;
1487 const double VP2a1 = +sphi * (K1P2 + K3P2);
1488 const double HP2a1 = -cphi * (K1P2 + K3P2);
1489 const double DP2a1 = VP2a1 + HP2a1;
1490 const double VP3a1 = +sphi * (K1P3 + K3P3);
1491 const double HP3a1 = -cphi * (K1P3 + K3P3);
1492 const double DP3a1 = VP3a1 + HP3a1;
1493
1494 const double VP0na1 = +sphi * (K1P0n + K3P0n);
1495 const double HP0na1 = -cphi * (K1P0n + K3P0n);
1496 const double DP0na1 = VP0na1 + HP0na1;
1497 const double VP1na1 = +sphi * (K1P1n + K3P1n);
1498 const double HP1na1 = -cphi * (K1P1n + K3P1n);
1499 const double DP1na1 = VP1na1 + HP1na1;
1500 const double VP2na1 = +sphi * (K1P2n + K3P2n);
1501 const double HP2na1 = -cphi * (K1P2n + K3P2n);
1502 const double DP2na1 = VP2na1 + HP2na1;
1503 const double VP3na1 = +sphi * (K1P3n + K3P3n);
1504 const double HP3na1 = -cphi * (K1P3n + K3P3n);
1505 const double DP3na1 = VP3na1 + HP3na1;
1506
1507 const double VA0 = VA0a0 * 1.5 - VA0a1 / 2 + 2 * dzvert * K2A0;
1508 const double HA0 = HA0a0 * 1.5 - HA0a1 / 2 + 2 * dzhor * K2A0;
1509 const double DA0 = VA0 + HA0;
1510 const double VZA0 = VA0 + K2A0;
1511 const double HZA0 = HA0 + K2A0;
1512 const double DZA0 = DA0 + K2A0;
1513 const double VA1 = VA1a0 * 1.5 - VA1a1 / 2 + 2 * dzvert * K2A1;
1514 const double HA1 = HA1a0 * 1.5 - HA1a1 / 2 + 2 * dzhor * K2A1;
1515 const double DA1 = VA1 + HA1;
1516 const double VZA1 = VA1 + K2A1;
1517 const double HZA1 = HA1 + K2A1;
1518 const double DZA1 = DA1 + K2A1;
1519 const double VA2 = VA2a0 * 1.5 - VA2a1 / 2 + 2 * dzvert * K2A2;
1520 const double HA2 = HA2a0 * 1.5 - HA2a1 / 2 + 2 * dzhor * K2A2;
1521 const double DA2 = VA2 + HA2;
1522 const double VZA2 = VA2 + K2A2;
1523 const double HZA2 = HA2 + K2A2;
1524 const double DZA2 = DA2 + K2A2;
1525 const double VA3 = VA3a0 * 1.5 - VA3a1 / 2 + 2 * dzvert * K2A3;
1526 const double HA3 = HA3a0 * 1.5 - HA3a1 / 2 + 2 * dzhor * K2A3;
1527 const double DA3 = VA3 + HA3;
1528 const double VZA3 = VA3 + K2A3;
1529 const double HZA3 = HA3 + K2A3;
1530 const double DZA3 = DA3 + K2A3;
1531
1532 const double VA0n = VA0na0 * 1.5 - VA0na1 / 2 + 2 * dzvert * K2A0n;
1533 const double HA0n = HA0na0 * 1.5 - HA0na1 / 2 + 2 * dzhor * K2A0n;
1534 const double DA0n = VA0n + HA0n;
1535 const double VZA0n = VA0n + K2A0n;
1536 const double HZA0n = HA0n + K2A0n;
1537 const double DZA0n = DA0n + K2A0n;
1538 const double VA1n = VA1na0 * 1.5 - VA1na1 / 2 + 2 * dzvert * K2A1n;
1539 const double HA1n = HA1na0 * 1.5 - HA1na1 / 2 + 2 * dzhor * K2A1n;
1540 const double DA1n = VA1n + HA1n;
1541 const double VZA1n = VA1n + K2A1n;
1542 const double HZA1n = HA1n + K2A1n;
1543 const double DZA1n = DA1n + K2A1n;
1544 const double VA2n = VA2na0 * 1.5 - VA2na1 / 2 + 2 * dzvert * K2A2n;
1545 const double HA2n = HA2na0 * 1.5 - HA2na1 / 2 + 2 * dzhor * K2A2n;
1546 const double DA2n = VA2n + HA2n;
1547 const double VZA2n = VA2n + K2A2n;
1548 const double HZA2n = HA2n + K2A2n;
1549 const double DZA2n = DA2n + K2A2n;
1550 const double VA3n = VA3na0 * 1.5 - VA3na1 / 2 + 2 * dzvert * K2A3n;
1551 const double HA3n = HA3na0 * 1.5 - HA3na1 / 2 + 2 * dzhor * K2A3n;
1552 const double DA3n = VA3n + HA3n;
1553 const double VZA3n = VA3n + K2A3n;
1554 const double HZA3n = HA3n + K2A3n;
1555 const double DZA3n = DA3n + K2A3n;
1556
1557 const double VP0 = VP0a0 * 1.5 - VP0a1 / 2 + 2 * dzvert * K2P0;
1558 const double HP0 = HP0a0 * 1.5 - HP0a1 / 2 + 2 * dzhor * K2P0;
1559 const double DP0 = VP0 + HP0;
1560 const double VZP0 = VP0 + K2P0;
1561 const double HZP0 = HP0 + K2P0;
1562 const double DZP0 = DP0 + K2P0;
1563 const double VP1 = VP1a0 * 1.5 - VP1a1 / 2 + 2 * dzvert * K2P1;
1564 const double HP1 = HP1a0 * 1.5 - HP1a1 / 2 + 2 * dzhor * K2P1;
1565 const double DP1 = VP1 + HP1;
1566 const double VZP1 = VP1 + K2P1;
1567 const double HZP1 = HP1 + K2P1;
1568 const double DZP1 = DP1 + K2P1;
1569 const double VP2 = VP2a0 * 1.5 - VP2a1 / 2 + 2 * dzvert * K2P2;
1570 const double HP2 = HP2a0 * 1.5 - HP2a1 / 2 + 2 * dzhor * K2P2;
1571 const double DP2 = VP2 + HP2;
1572 const double VZP2 = VP2 + K2P2;
1573 const double HZP2 = HP2 + K2P2;
1574 const double DZP2 = DP2 + K2P2;
1575 const double VP3 = VP3a0 * 1.5 - VP3a1 / 2 + 2 * dzvert * K2P3;
1576 const double HP3 = HP3a0 * 1.5 - HP3a1 / 2 + 2 * dzhor * K2P3;
1577 const double DP3 = VP3 + HP3;
1578 const double VZP3 = VP3 + K2P3;
1579 const double HZP3 = HP3 + K2P3;
1580 const double DZP3 = DP3 + K2P3;
1581
1582 const double VP0n = VP0na0 * 1.5 - VP0na1 / 2 + 2 * dzvert * K2P0n;
1583 const double HP0n = HP0na0 * 1.5 - HP0na1 / 2 + 2 * dzhor * K2P0n;
1584 const double DP0n = VP0n + HP0n;
1585 const double VZP0n = VP0n + K2P0n;
1586 const double HZP0n = HP0n + K2P0n;
1587 const double DZP0n = DP0n + K2P0n;
1588 const double VP1n = VP1na0 * 1.5 - VP1na1 / 2 + 2 * dzvert * K2P1n;
1589 const double HP1n = HP1na0 * 1.5 - HP1na1 / 2 + 2 * dzhor * K2P1n;
1590 const double DP1n = VP1n + HP1n;
1591 const double VZP1n = VP1n + K2P1n;
1592 const double HZP1n = HP1n + K2P1n;
1593 const double DZP1n = DP1n + K2P1n;
1594 const double VP2n = VP2na0 * 1.5 - VP2na1 / 2 + 2 * dzvert * K2P2n;
1595 const double HP2n = HP2na0 * 1.5 - HP2na1 / 2 + 2 * dzhor * K2P2n;
1596 const double DP2n = VP2n + HP2n;
1597 const double VZP2n = VP2n + K2P2n;
1598 const double HZP2n = HP2n + K2P2n;
1599 const double DZP2n = DP2n + K2P2n;
1600 const double VP3n = VP3na0 * 1.5 - VP3na1 / 2 + 2 * dzvert * K2P3n;
1601 const double HP3n = HP3na0 * 1.5 - HP3na1 / 2 + 2 * dzhor * K2P3n;
1602 const double DP3n = VP3n + HP3n;
1603 const double VZP3n = VP3n + K2P3n;
1604 const double HZP3n = HP3n + K2P3n;
1605 const double DZP3n = DP3n + K2P3n;
1606
1607 // Initial values of update values (Up)
1608
1609 double A0a0 = Projptr[0][0][0][1] + ds * K1A0;
1610 double A0a1 = Projptr[0][0][0][3] + ds * (K1A0 + K3A0);
1611 double A2a0 = Projptr[0][2][0][1] + ds * K1A2;
1612 double A2a1 = Projptr[0][2][0][3] + ds * (K1A2 + K3A2);
1613
1614 double P0na0 = Projptr[1][0][1][1] + ds * K1P0n;
1615 double P0na1 = Projptr[1][0][1][3] + ds * (K1P0n + K3P0n);
1616 double P2na0 = Projptr[1][2][1][1] + ds * K1P2n;
1617 double P2na1 = Projptr[1][2][1][3] + ds * (K1P2n + K3P2n);
1618
1619 double A0na0 = Projptr[1][0][0][1] + ds * K1A0n;
1620 double A0na1 = Projptr[1][0][0][3] + ds * (K1A0n + K3A0n);
1621 double A2na0 = Projptr[1][2][0][1] + ds * K1A2n;
1622 double A2na1 = Projptr[1][2][0][3] + ds * (K1A2n + K3A2n);
1623
1624 double P0a0 = Projptr[0][0][1][1] + ds * K1P0;
1625 double P0a1 = Projptr[0][0][1][3] + ds * (K1P0 + K3P0);
1626 double P2a0 = Projptr[0][2][1][1] + ds * K1P2;
1627 double P2a1 = Projptr[0][2][1][3] + ds * (K1P2 + K3P2);
1628
1629 double A1a0 = Projptr[0][1][0][1] + ds * K1A1;
1630 double A1a1 = Projptr[0][1][0][3] + ds * (K1A1 + K3A1);
1631 double A3a0 = Projptr[0][3][0][1] + ds * K1A3;
1632 double A3a1 = Projptr[0][3][0][3] + ds * (K1A3 + K3A3);
1633
1634 double P1na0 = Projptr[1][1][1][1] + ds * K1P1n;
1635 double P1na1 = Projptr[1][1][1][3] + ds * (K1P1n + K3P1n);
1636 double P3na0 = Projptr[1][3][1][1] + ds * K1P3n;
1637 double P3na1 = Projptr[1][3][1][3] + ds * (K1P3n + K3P3n);
1638
1639 double A1na0 = Projptr[1][1][0][1] + ds * K1A1n;
1640 double A1na1 = Projptr[1][1][0][3] + ds * (K1A1n + K3A1n);
1641 double A3na0 = Projptr[1][3][0][1] + ds * K1A3n;
1642 double A3na1 = Projptr[1][3][0][3] + ds * (K1A3n + K3A3n);
1643
1644 double P1a0 = Projptr[0][1][1][1] + ds * K1P1;
1645 double P1a1 = Projptr[0][1][1][3] + ds * (K1P1 + K3P1);
1646 double P3a0 = Projptr[0][3][1][1] + ds * K1P3;
1647 double P3a1 = Projptr[0][3][1][3] + ds * (K1P3 + K3P3);
1648
1649 double UpA0 = 2 * (Projptr[0][0][0][1] + ds * K1A0 + dz * K2A0) - (A0a0 + A0a1) / 2;
1650 double UpA1 = 2 * (Projptr[0][1][0][1] + ds * K1A1 + dz * K2A1) - (A1a0 + A1a1) / 2;
1651 double UpA2 = 2 * (Projptr[0][2][0][1] + ds * K1A2 + dz * K2A2) - (A2a0 + A2a1) / 2;
1652 double UpA3 = 2 * (Projptr[0][3][0][1] + ds * K1A3 + dz * K2A3) - (A3a0 + A3a1) / 2;
1653
1654 double UpA0n = 2 * (Projptr[1][0][0][1] + ds * K1A0n + dz * K2A0n) - (A0na0 + A0na1) / 2;
1655 double UpA1n = 2 * (Projptr[1][1][0][1] + ds * K1A1n + dz * K2A1n) - (A1na0 + A1na1) / 2;
1656 double UpA2n = 2 * (Projptr[1][2][0][1] + ds * K1A2n + dz * K2A2n) - (A2na0 + A2na1) / 2;
1657 double UpA3n = 2 * (Projptr[1][3][0][1] + ds * K1A3n + dz * K2A3n) - (A3na0 + A3na1) / 2;
1658
1659 double UpP0 = 2 * (Projptr[0][0][1][1] + ds * K1P0 + dz * K2P0) - (P0a0 + P0a1) / 2;
1660 double UpP1 = 2 * (Projptr[0][1][1][1] + ds * K1P1 + dz * K2P1) - (P1a0 + P1a1) / 2;
1661 double UpP2 = 2 * (Projptr[0][2][1][1] + ds * K1P2 + dz * K2P2) - (P2a0 + P2a1) / 2;
1662 double UpP3 = 2 * (Projptr[0][3][1][1] + ds * K1P3 + dz * K2P3) - (P3a0 + P3a1) / 2;
1663
1664 double UpP0n = 2 * (Projptr[1][0][1][1] + ds * K1P0n + dz * K2P0n) - (P0na0 + P0na1) / 2;
1665 double UpP1n = 2 * (Projptr[1][1][1][1] + ds * K1P1n + dz * K2P1n) - (P1na0 + P1na1) / 2;
1666 double UpP2n = 2 * (Projptr[1][2][1][1] + ds * K1P2n + dz * K2P2n) - (P2na0 + P2na1) / 2;
1667 double UpP3n = 2 * (Projptr[1][3][1][1] + ds * K1P3n + dz * K2P3n) - (P3na0 + P3na1) / 2;
1668
1669#endif
1670
1671 // some extra start values
1672
1673 // Find symmetric value in Z by 'mirroring' it around the centre z of the LORs:
1674 // Z+Q = 2*centre_of_LOR_in_image_coordinates
1675 // Note that we are backprojecting ring0 and ring0+1, so we mirror around ring0+0.5
1676 // original Q = (int) (4*ring0+2*delta+2-Z + 0.5);
1677 // CL&KT 21/12/99 added axial_pos_to_z_offset and num_planes_per_physical_ring
1678 {
1679 // first compute it as floating point (although it has to be an int really)
1680 const float Qf
1681 = (2 * num_planes_per_axial_pos * (ring0 + 0.5) + num_planes_per_physical_ring * delta + 2 * axial_pos_to_z_offset - Z);
1682 // now use rounding to be safe
1683 Q = (int)floor(Qf + 0.5);
1684 assert(fabs(Q - Qf) < 10E-4);
1685 }
1686
1687 dzdiag = dzvert + dzhor;
1688 dsdiag = -cphi + sphi;
1689
1690 /* KT 13/05/98 changed loop condition, originally a combination of
1691 while (X>X2||Y<Y2||Z<Z2) {
1692 // code which increments Y,Z or decrements X
1693 if (X<X2||Y>Y2||Z>Z2)
1694 }
1695 this had problems for nearly horizontal or vertical lines.
1696 For example, while Y==Y2+1, some extra iterations had to be done
1697 on X.
1698 Now I break out of the while when the voxel goes out of the cylinder,
1699 which means I don't have to use X2,Y2,Z2 anymore
1700 */
1701 do
1702 {
1703 assert(ds >= 0);
1704 assert(ds <= 1);
1705 assert(dz >= 0);
1706 assert(dz <= ring_unit + epsilon);
1707
1708 // Update voxel values for this X,Y,Z
1709 // For 1 given (X,Y)-position, there are always 2 voxels along the z-axis
1710 // in this beam.
1711 const int Zplus = Z + 1;
1712 const int Qmin = Q - 1;
1713
1714#if PIECEWISE_INTERPOLATION
1715
1716 const double twodsdz = 2 * ds * dz;
1717 const double twodsdz2 = 2 * ds * (dz + 0.5);
1718 // KT 16/06/98 changed check ds!=0 to fabs(ds)>epsilon for better rounding control
1719 const bool do_s_symmetry = (s != 0 || fabs(ds) > epsilon);
1720
1721 if (Z >= minplane && Z <= maxplane)
1722 {
1723 image[Z][Y][X] += (dz <= 0.25) ? A0a0 : UpA0 + twodsdz * K3A0;
1724 image[Z][X][-Y] += (dz <= 0.25) ? A2a0 : UpA2 + twodsdz * K3A2;
1725 image[Z][X][Y] += (dz <= 0.25) ? A1na0 : UpA1n + twodsdz * K3A1n;
1726 image[Z][Y][-X] += (dz <= 0.25) ? A3na0 : UpA3n + twodsdz * K3A3n;
1727 if (do_s_symmetry)
1728 {
1729 image[Z][-X][-Y] += (dz <= 0.25) ? P1a0 : UpP1 + twodsdz * K3P1;
1730 image[Z][-Y][X] += (dz <= 0.25) ? P3a0 : UpP3 + twodsdz * K3P3;
1731 image[Z][-Y][-X] += (dz <= 0.25) ? P0na0 : UpP0n + twodsdz * K3P0n;
1732 image[Z][-X][Y] += (dz <= 0.25) ? P2na0 : UpP2n + twodsdz * K3P2n;
1733 }
1734 }
1735 if (Zplus >= minplane && Zplus <= maxplane)
1736 {
1737 image[Zplus][Y][X] += (dz >= 0.25) ? A0a1 : UpA0 + twodsdz2 * K3A0 + ZplusKorrA0;
1738 image[Zplus][X][-Y] += (dz >= 0.25) ? A2a1 : UpA2 + twodsdz2 * K3A2 + ZplusKorrA2;
1739 image[Zplus][X][Y] += (dz >= 0.25) ? A1na1 : UpA1n + twodsdz2 * K3A1n + ZplusKorrA1n;
1740 image[Zplus][Y][-X] += (dz >= 0.25) ? A3na1 : UpA3n + twodsdz2 * K3A3n + ZplusKorrA3n;
1741 if (do_s_symmetry)
1742 {
1743 image[Zplus][-X][-Y] += (dz >= 0.25) ? P1a1 : UpP1 + twodsdz2 * K3P1 + ZplusKorrP1;
1744 image[Zplus][-Y][X] += (dz >= 0.25) ? P3a1 : UpP3 + twodsdz2 * K3P3 + ZplusKorrP3;
1745 image[Zplus][-Y][-X] += (dz >= 0.25) ? P0na1 : UpP0n + twodsdz2 * K3P0n + ZplusKorrP0n;
1746 image[Zplus][-X][Y] += (dz >= 0.25) ? P2na1 : UpP2n + twodsdz2 * K3P2n + ZplusKorrP2n;
1747 }
1748 }
1749 if (Q >= minplane && Q <= maxplane)
1750 {
1751 image[Q][Y][-X] += (dz <= 0.25) ? A3a0 : UpA3 + twodsdz * K3A3;
1752 image[Q][Y][X] += (dz <= 0.25) ? A0na0 : UpA0n + twodsdz * K3A0n;
1753 image[Q][X][-Y] += (dz <= 0.25) ? A2na0 : UpA2n + twodsdz * K3A2n;
1754 image[Q][X][Y] += (dz <= 0.25) ? A1a0 : UpA1 + twodsdz * K3A1;
1755 if (do_s_symmetry)
1756 {
1757 image[Q][-Y][-X] += (dz <= 0.25) ? P0a0 : UpP0 + twodsdz * K3P0;
1758 image[Q][-X][Y] += (dz <= 0.25) ? P2a0 : UpP2 + twodsdz * K3P2;
1759 image[Q][-X][-Y] += (dz <= 0.25) ? P1na0 : UpP1n + twodsdz * K3P1n;
1760 image[Q][-Y][X] += (dz <= 0.25) ? P3na0 : UpP3n + twodsdz * K3P3n;
1761 }
1762 }
1763 if (Qmin >= minplane && Qmin <= maxplane)
1764 {
1765 image[Qmin][Y][-X] += (dz >= 0.25) ? A3a1 : UpA3 + twodsdz2 * K3A3 + ZplusKorrA3;
1766 image[Qmin][Y][X] += (dz >= 0.25) ? A0na1 : UpA0n + twodsdz2 * K3A0n + ZplusKorrA0n;
1767 image[Qmin][X][-Y] += (dz >= 0.25) ? A2na1 : UpA2n + twodsdz2 * K3A2n + ZplusKorrA2n;
1768 image[Qmin][X][Y] += (dz >= 0.25) ? A1a1 : UpA1 + twodsdz2 * K3A1 + ZplusKorrA1;
1769 if (do_s_symmetry)
1770 {
1771 image[Qmin][-Y][-X] += (dz >= 0.25) ? P0a1 : UpP0 + twodsdz2 * K3P0 + ZplusKorrP0;
1772 image[Qmin][-X][Y] += (dz >= 0.25) ? P2a1 : UpP2 + twodsdz2 * K3P2 + ZplusKorrP2;
1773 image[Qmin][-X][-Y] += (dz >= 0.25) ? P1na1 : UpP1n + twodsdz2 * K3P1n + ZplusKorrP1n;
1774 image[Qmin][-Y][X] += (dz >= 0.25) ? P3na1 : UpP3n + twodsdz2 * K3P3n + ZplusKorrP3n;
1775 }
1776 }
1777#else // !PIECEWISE_INTERPOLATION
1778# ifdef ALTERNATIVE
1779 const double dsdz = ds * dz;
1780 const double dsdz2 = ds * (dz + 0.5);
1781 // KT 16/06/98 changed check ds!=0 to fabs(ds)>epsilon for better rounding control
1782 const bool do_s_symmetry = (s != 0 || fabs(ds) > epsilon);
1783
1784 if (Z >= minplane && Z <= maxplane)
1785 {
1786 image[Z][Y][X] += UpA0 + dsdz * K3A0;
1787 image[Z][X][-Y] += UpA2 + dsdz * K3A2;
1788 image[Z][X][Y] += UpA1n + dsdz * K3A1n;
1789 image[Z][Y][-X] += UpA3n + dsdz * K3A3n;
1790 if (do_s_symmetry)
1791 {
1792 image[Z][-X][-Y] += UpP1 + dsdz * K3P1;
1793 image[Z][-Y][X] += UpP3 + dsdz * K3P3;
1794 image[Z][-Y][-X] += UpP0n + dsdz * K3P0n;
1795 image[Z][-X][Y] += UpP2n + dsdz * K3P2n;
1796 }
1797 }
1798 if (Zplus >= minplane && Zplus <= maxplane)
1799 {
1800 image[Zplus][Y][X] += UpA0 + dsdz2 * K3A0 + ZplusKorrA0;
1801 image[Zplus][X][-Y] += UpA2 + dsdz2 * K3A2 + ZplusKorrA2;
1802 image[Zplus][X][Y] += UpA1n + dsdz2 * K3A1n + ZplusKorrA1n;
1803 image[Zplus][Y][-X] += UpA3n + dsdz2 * K3A3n + ZplusKorrA3n;
1804 if (do_s_symmetry)
1805 {
1806 image[Zplus][-X][-Y] += UpP1 + dsdz2 * K3P1 + ZplusKorrP1;
1807 image[Zplus][-Y][X] += UpP3 + dsdz2 * K3P3 + ZplusKorrP3;
1808 image[Zplus][-Y][-X] += UpP0n + dsdz2 * K3P0n + ZplusKorrP0n;
1809 image[Zplus][-X][Y] += UpP2n + dsdz2 * K3P2n + ZplusKorrP2n;
1810 }
1811 }
1812 if (Q >= minplane && Q <= maxplane)
1813 {
1814 image[Q][Y][-X] += UpA3 + dsdz * K3A3;
1815 image[Q][Y][X] += UpA0n + dsdz * K3A0n;
1816 image[Q][X][-Y] += UpA2n + dsdz * K3A2n;
1817 image[Q][X][Y] += UpA1 + dsdz * K3A1;
1818 if (do_s_symmetry)
1819 {
1820 image[Q][-Y][-X] += UpP0 + dsdz * K3P0;
1821 image[Q][-X][Y] += UpP2 + dsdz * K3P2;
1822 image[Q][-X][-Y] += UpP1n + dsdz * K3P1n;
1823 image[Q][-Y][X] += UpP3n + dsdz * K3P3n;
1824 }
1825 }
1826 if (Qmin >= minplane && Qmin <= maxplane)
1827 {
1828 image[Qmin][Y][-X] += UpA3 + dsdz2 * K3A3 + ZplusKorrA3;
1829 image[Qmin][Y][X] += UpA0n + dsdz2 * K3A0n + ZplusKorrA0n;
1830 image[Qmin][X][-Y] += UpA2n + dsdz2 * K3A2n + ZplusKorrA2n;
1831 image[Qmin][X][Y] += UpA1 + dsdz2 * K3A1 + ZplusKorrA1;
1832 if (do_s_symmetry)
1833 {
1834 image[Qmin][-Y][-X] += UpP0 + dsdz2 * K3P0 + ZplusKorrP0;
1835 image[Qmin][-X][Y] += UpP2 + dsdz2 * K3P2 + ZplusKorrP2;
1836 image[Qmin][-X][-Y] += UpP1n + dsdz2 * K3P1n + ZplusKorrP1n;
1837 image[Qmin][-Y][X] += UpP3n + dsdz2 * K3P3n + ZplusKorrP3n;
1838 }
1839 }
1840# else // ALTERNATIVE
1841 double TMP1, TMP2;
1842 TMP1 = ds * K3A0;
1843 TMP2 = UpA0 + dz * TMP1;
1844 if (Z >= minplane && Z <= maxplane)
1845 image[Z][Y][X] += TMP2;
1846
1847 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
1848 // as there is only one voxel in the beam in slice unit
1849 if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5)
1850 image[Zplus][Y][X] += TMP2 + ring_unit * TMP1 + ZplusKorrA0;
1851
1852 TMP1 = ds * K3A1;
1853 TMP2 = UpA1 + dz * TMP1;
1854 if (Q >= minplane && Q <= maxplane)
1855 image[Q][X][Y] += TMP2;
1856 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
1857 // as there is only one voxel in the beam in slice unit
1858 if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5)
1859 image[Qmin][X][Y] += TMP2 + ring_unit * TMP1 + ZplusKorrA1;
1860
1861 TMP1 = ds * K3A2;
1862 TMP2 = UpA2 + dz * TMP1;
1863 if (Z >= minplane && Z <= maxplane)
1864 image[Z][X][-Y] += TMP2;
1865 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
1866 // as there is only one voxel in the beam in slice unit
1867 if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5)
1868 image[Zplus][X][-Y] += TMP2 + ring_unit * TMP1 + ZplusKorrA2;
1869 TMP1 = ds * K3A3;
1870 TMP2 = UpA3 + dz * TMP1;
1871 if (Q >= minplane && Q <= maxplane)
1872 image[Q][Y][-X] += TMP2;
1873 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
1874 // as there is only one voxel in the beam in slice unit
1875 if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5)
1876 image[Qmin][Y][-X] += TMP2 + ring_unit * TMP1 + ZplusKorrA3;
1877
1878 TMP1 = ds * K3A0n;
1879 TMP2 = UpA0n + dz * TMP1;
1880 if (Q >= minplane && Q <= maxplane)
1881 image[Q][Y][X] += TMP2;
1882 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
1883 // as there is only one voxel in the beam in slice unit
1884 if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5)
1885 image[Qmin][Y][X] += TMP2 + ring_unit * TMP1 + ZplusKorrA0n;
1886 TMP1 = ds * K3A1n;
1887 TMP2 = UpA1n + dz * TMP1;
1888 if (Z >= minplane && Z <= maxplane)
1889 image[Z][X][Y] += TMP2;
1890 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
1891 // as there is only one voxel in the beam in slice unit
1892 if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5)
1893 image[Zplus][X][Y] += TMP2 + ring_unit * TMP1 + ZplusKorrA1n;
1894 TMP1 = ds * K3A2n;
1895 TMP2 = UpA2n + dz * TMP1;
1896 if (Q >= minplane && Q <= maxplane)
1897 image[Q][X][-Y] += TMP2;
1898 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
1899 // as there is only one voxel in the beam in slice unit
1900 if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5)
1901 image[Qmin][X][-Y] += TMP2 + ring_unit * TMP1 + ZplusKorrA2n;
1902 TMP1 = ds * K3A3n;
1903 TMP2 = UpA3n + dz * TMP1;
1904 if (Z >= minplane && Z <= maxplane)
1905 image[Z][Y][-X] += TMP2;
1906 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
1907 // as there is only one voxel in the beam in slice unit
1908 if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5)
1909 image[Zplus][Y][-X] += TMP2 + ring_unit * TMP1 + ZplusKorrA3n;
1910
1911 // KT 16/06/98 changed check ds!=0 to fabs(ds)>epsilon for better rounding control
1912 if (s != 0 || fabs(ds) > epsilon)
1913 {
1914 TMP1 = ds * K3P0;
1915 TMP2 = UpP0 + dz * TMP1;
1916 if (Q >= minplane && Q <= maxplane)
1917 image[Q][-Y][-X] += TMP2;
1918 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
1919 // as there is only one voxel in the beam in slice unit
1920 if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5)
1921 image[Qmin][-Y][-X] += TMP2 + ring_unit * TMP1 + ZplusKorrP0;
1922 TMP1 = ds * K3P1;
1923 TMP2 = UpP1 + dz * TMP1;
1924 if (Z >= minplane && Z <= maxplane)
1925 image[Z][-X][-Y] += TMP2;
1926 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
1927 // as there is only one voxel in the beam in slice unit
1928 if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5)
1929 image[Zplus][-X][-Y] += TMP2 + ring_unit * TMP1 + ZplusKorrP1;
1930 TMP1 = ds * K3P2;
1931 TMP2 = UpP2 + dz * TMP1;
1932 if (Q >= minplane && Q <= maxplane)
1933 image[Q][-X][Y] += TMP2;
1934 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
1935 // as there is only one voxel in the beam in slice unit
1936 if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5)
1937 image[Qmin][-X][Y] += TMP2 + ring_unit * TMP1 + ZplusKorrP2;
1938 TMP1 = ds * K3P3;
1939 TMP2 = UpP3 + dz * TMP1;
1940 if (Z >= minplane && Z <= maxplane)
1941 image[Z][-Y][X] += TMP2;
1942 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
1943 // as there is only one voxel in the beam in slice unit
1944 if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5)
1945 image[Zplus][-Y][X] += TMP2 + ring_unit * TMP1 + ZplusKorrP3;
1946
1947 TMP1 = ds * K3P0n;
1948 TMP2 = UpP0n + dz * TMP1;
1949 if (Z >= minplane && Z <= maxplane)
1950 image[Z][-Y][-X] += TMP2;
1951 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
1952 // as there is only one voxel in the beam in slice unit
1953 if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5)
1954 image[Zplus][-Y][-X] += TMP2 + ring_unit * TMP1 + ZplusKorrP0n;
1955 TMP1 = ds * K3P1n;
1956 TMP2 = UpP1n + dz * TMP1;
1957 if (Q >= minplane && Q <= maxplane)
1958 image[Q][-X][-Y] += TMP2;
1959 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
1960 // as there is only one voxel in the beam in slice unit
1961 if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5)
1962 image[Qmin][-X][-Y] += TMP2 + ring_unit * TMP1 + ZplusKorrP1n;
1963 TMP1 = ds * K3P2n;
1964 TMP2 = UpP2n + dz * TMP1;
1965 if (Z >= minplane && Z <= maxplane)
1966 image[Z][-X][Y] += TMP2;
1967 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
1968 // as there is only one voxel in the beam in slice unit
1969 if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5)
1970 image[Zplus][-X][Y] += TMP2 + ring_unit * TMP1 + ZplusKorrP2n;
1971 TMP1 = ds * K3P3n;
1972 TMP2 = UpP3n + dz * TMP1;
1973 if (Q >= minplane && Q <= maxplane)
1974 image[Q][-Y][X] += TMP2;
1975 // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data
1976 // as there is only one voxel in the beam in slice unit
1977 if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5)
1978 image[Qmin][-Y][X] += TMP2 + ring_unit * TMP1 + ZplusKorrP3n;
1979 }
1980
1981# endif // ALTERNATIVE
1982#endif // PIECEWISE_INTERPOLATION
1983
1984 // Search for next pixel in the beam
1985
1986 if (ds >= cphi)
1987 {
1988 /* horizontal*/
1989 X -= 1;
1990 ds -= cphi;
1991 dz += dzhor;
1992 if (dz < epsilon)
1993 { /* increment Z */
1994 Z++;
1995 Q--;
1996 dz += ring_unit;
1997 UpA0 += HZA0;
1998 UpA1 += HZA1;
1999 UpA2 += HZA2;
2000 UpA3 += HZA3;
2001 UpA0n += HZA0n;
2002 UpA1n += HZA1n;
2003 UpA2n += HZA2n;
2004 UpA3n += HZA3n;
2005 UpP0 += HZP0;
2006 UpP1 += HZP1;
2007 UpP2 += HZP2;
2008 UpP3 += HZP3;
2009 UpP0n += HZP0n;
2010 UpP1n += HZP1n;
2011 UpP2n += HZP2n;
2012 UpP3n += HZP3n;
2013#ifdef MOREZ
2014 while (dz < epsilon)
2015 {
2016 Z++;
2017 Q--;
2018 dz += ring_unit;
2019 UpA0 += HZA0 - HA0;
2020 UpA1 += HZA1 - HA1;
2021 UpA2 += HZA2 - HA2;
2022 UpA3 += HZA3 - HA3;
2023 UpA0n += HZA0n - HA0n;
2024 UpA1n += HZA1n - HA1n;
2025 UpA2n += HZA2n - HA2n;
2026 UpA3n += HZA3n - HA3n;
2027 UpP0 += HZP0 - HP0;
2028 UpP1 += HZP1 - HP1;
2029 UpP2 += HZP2 - HP2;
2030 UpP3 += HZP3 - HP3;
2031 UpP0n += HZP0n - HP0n;
2032 UpP1n += HZP1n - HP1n;
2033 UpP2n += HZP2n - HP2n;
2034 UpP3n += HZP3n - HP3n;
2035 }
2036#endif
2037 }
2038
2039 else
2040 { /* Z does not change */
2041 UpA0 += HA0;
2042 UpA1 += HA1;
2043 UpA2 += HA2;
2044 UpA3 += HA3;
2045 UpA0n += HA0n;
2046 UpA1n += HA1n;
2047 UpA2n += HA2n;
2048 UpA3n += HA3n;
2049 UpP0 += HP0;
2050 UpP1 += HP1;
2051 UpP2 += HP2;
2052 UpP3 += HP3;
2053 UpP0n += HP0n;
2054 UpP1n += HP1n;
2055 UpP2n += HP2n;
2056 UpP3n += HP3n;
2057 }
2058#if PIECEWISE_INTERPOLATION
2059 A0a0 += HA0a0;
2060 A1a0 += HA1a0;
2061 A2a0 += HA2a0;
2062 A3a0 += HA3a0;
2063 A0na0 += HA0na0;
2064 A1na0 += HA1na0;
2065 A2na0 += HA2na0;
2066 A3na0 += HA3na0;
2067 P0a0 += HP0a0;
2068 P1a0 += HP1a0;
2069 P2a0 += HP2a0;
2070 P3a0 += HP3a0;
2071 P0na0 += HP0na0;
2072 P1na0 += HP1na0;
2073 P2na0 += HP2na0;
2074 P3na0 += HP3na0;
2075
2076 A0a1 += HA0a1;
2077 A1a1 += HA1a1;
2078 A2a1 += HA2a1;
2079 A3a1 += HA3a1;
2080 A0na1 += HA0na1;
2081 A1na1 += HA1na1;
2082 A2na1 += HA2na1;
2083 A3na1 += HA3na1;
2084 P0a1 += HP0a1;
2085 P1a1 += HP1a1;
2086 P2a1 += HP2a1;
2087 P3a1 += HP3a1;
2088 P0na1 += HP0na1;
2089 P1na1 += HP1na1;
2090 P2na1 += HP2na1;
2091 P3na1 += HP3na1;
2092#endif // PIECEWISE_INTERPOLATION
2093 }
2094 // KT 14/05/98 use < instead of <= (see formula 6.17 in Egger's thesis)
2095 else if (ds < 1 - sphi)
2096 {
2097 /* vertical*/
2098 Y += 1;
2099 ds += sphi;
2100 dz += dzvert;
2101 if (dz < epsilon)
2102 { /* increment Z */
2103 Z++;
2104 Q--;
2105 dz += ring_unit;
2106 UpA0 += VZA0;
2107 UpA1 += VZA1;
2108 UpA2 += VZA2;
2109 UpA3 += VZA3;
2110 UpA0n += VZA0n;
2111 UpA1n += VZA1n;
2112 UpA2n += VZA2n;
2113 UpA3n += VZA3n;
2114 UpP0 += VZP0;
2115 UpP1 += VZP1;
2116 UpP2 += VZP2;
2117 UpP3 += VZP3;
2118 UpP0n += VZP0n;
2119 UpP1n += VZP1n;
2120 UpP2n += VZP2n;
2121 UpP3n += VZP3n;
2122#ifdef MOREZ
2123 while (dz < epsilon)
2124 {
2125 Z++;
2126 Q--;
2127 dz += ring_unit;
2128 UpA0 += VZA0 - VA0;
2129 UpA1 += VZA1 - VA1;
2130 UpA2 += VZA2 - VA2;
2131 UpA3 += VZA3 - VA3;
2132 UpA0n += VZA0n - VA0n;
2133 UpA1n += VZA1n - VA1n;
2134 UpA2n += VZA2n - VA2n;
2135 UpA3n += VZA3n - VA3n;
2136 UpP0 += VZP0 - VP0;
2137 UpP1 += VZP1 - VP1;
2138 UpP2 += VZP2 - VP2;
2139 UpP3 += VZP3 - VP3;
2140 UpP0n += VZP0n - VP0n;
2141 UpP1n += VZP1n - VP1n;
2142 UpP2n += VZP2n - VP2n;
2143 UpP3n += VZP3n - VP3n;
2144 }
2145#endif
2146 }
2147 else
2148 { /* Wenn Z gleich bleibt */
2149 UpA0 += VA0;
2150 UpA1 += VA1;
2151 UpA2 += VA2;
2152 UpA3 += VA3;
2153 UpA0n += VA0n;
2154 UpA1n += VA1n;
2155 UpA2n += VA2n;
2156 UpA3n += VA3n;
2157 UpP0 += VP0;
2158 UpP1 += VP1;
2159 UpP2 += VP2;
2160 UpP3 += VP3;
2161 UpP0n += VP0n;
2162 UpP1n += VP1n;
2163 UpP2n += VP2n;
2164 UpP3n += VP3n;
2165 }
2166#if PIECEWISE_INTERPOLATION
2167 A0a0 += VA0a0;
2168 A1a0 += VA1a0;
2169 A2a0 += VA2a0;
2170 A3a0 += VA3a0;
2171 A0na0 += VA0na0;
2172 A1na0 += VA1na0;
2173 A2na0 += VA2na0;
2174 A3na0 += VA3na0;
2175 P0a0 += VP0a0;
2176 P1a0 += VP1a0;
2177 P2a0 += VP2a0;
2178 P3a0 += VP3a0;
2179 P0na0 += VP0na0;
2180 P1na0 += VP1na0;
2181 P2na0 += VP2na0;
2182 P3na0 += VP3na0;
2183
2184 A0a1 += VA0a1;
2185 A1a1 += VA1a1;
2186 A2a1 += VA2a1;
2187 A3a1 += VA3a1;
2188 A0na1 += VA0na1;
2189 A1na1 += VA1na1;
2190 A2na1 += VA2na1;
2191 A3na1 += VA3na1;
2192 P0a1 += VP0a1;
2193 P1a1 += VP1a1;
2194 P2a1 += VP2a1;
2195 P3a1 += VP3a1;
2196 P0na1 += VP0na1;
2197 P1na1 += VP1na1;
2198 P2na1 += VP2na1;
2199 P3na1 += VP3na1;
2200#endif // PIECEWISE_INTERPOLATION
2201 }
2202 else
2203 {
2204 /* diagonal*/
2205 X -= 1;
2206 Y += 1;
2207 ds += dsdiag;
2208 dz += dzdiag;
2209 if (dz < epsilon)
2210 { /* increment Z */
2211 Z++;
2212 Q--;
2213 dz += ring_unit;
2214 UpA0 += DZA0;
2215 UpA1 += DZA1;
2216 UpA2 += DZA2;
2217 UpA3 += DZA3;
2218 UpA0n += DZA0n;
2219 UpA1n += DZA1n;
2220 UpA2n += DZA2n;
2221 UpA3n += DZA3n;
2222 UpP0 += DZP0;
2223 UpP1 += DZP1;
2224 UpP2 += DZP2;
2225 UpP3 += DZP3;
2226 UpP0n += DZP0n;
2227 UpP1n += DZP1n;
2228 UpP2n += DZP2n;
2229 UpP3n += DZP3n;
2230#ifdef MOREZ
2231 while (dz < epsilon)
2232 {
2233 Z++;
2234 Q--;
2235 dz += ring_unit;
2236 UpA0 += DZA0 - DA0;
2237 UpA1 += DZA1 - DA1;
2238 UpA2 += DZA2 - DA2;
2239 UpA3 += DZA3 - DA3;
2240 UpA0n += DZA0n - DA0n;
2241 UpA1n += DZA1n - DA1n;
2242 UpA2n += DZA2n - DA2n;
2243 UpA3n += DZA3n - DA3n;
2244 UpP0 += DZP0 - DP0;
2245 UpP1 += DZP1 - DP1;
2246 UpP2 += DZP2 - DP2;
2247 UpP3 += DZP3 - DP3;
2248 UpP0n += DZP0n - DP0n;
2249 UpP1n += DZP1n - DP1n;
2250 UpP2n += DZP2n - DP2n;
2251 UpP3n += DZP3n - DP3n;
2252 }
2253#endif
2254 }
2255
2256 else
2257 { /* Z does not change */
2258 UpA0 += DA0;
2259 UpA1 += DA1;
2260 UpA2 += DA2;
2261 UpA3 += DA3;
2262 UpA0n += DA0n;
2263 UpA1n += DA1n;
2264 UpA2n += DA2n;
2265 UpA3n += DA3n;
2266 UpP0 += DP0;
2267 UpP1 += DP1;
2268 UpP2 += DP2;
2269 UpP3 += DP3;
2270 UpP0n += DP0n;
2271 UpP1n += DP1n;
2272 UpP2n += DP2n;
2273 UpP3n += DP3n;
2274 }
2275#if PIECEWISE_INTERPOLATION
2276 A0a0 += DA0a0;
2277 A1a0 += DA1a0;
2278 A2a0 += DA2a0;
2279 A3a0 += DA3a0;
2280 A0na0 += DA0na0;
2281 A1na0 += DA1na0;
2282 A2na0 += DA2na0;
2283 A3na0 += DA3na0;
2284 P0a0 += DP0a0;
2285 P1a0 += DP1a0;
2286 P2a0 += DP2a0;
2287 P3a0 += DP3a0;
2288 P0na0 += DP0na0;
2289 P1na0 += DP1na0;
2290 P2na0 += DP2na0;
2291 P3na0 += DP3na0;
2292
2293 A0a1 += DA0a1;
2294 A1a1 += DA1a1;
2295 A2a1 += DA2a1;
2296 A3a1 += DA3a1;
2297 A0na1 += DA0na1;
2298 A1na1 += DA1na1;
2299 A2na1 += DA2na1;
2300 A3na1 += DA3na1;
2301 P0a1 += DP0a1;
2302 P1a1 += DP1a1;
2303 P2a1 += DP2a1;
2304 P3a1 += DP3a1;
2305 P0na1 += DP0na1;
2306 P1na1 += DP1na1;
2307 P2na1 += DP2na1;
2308 P3na1 += DP3na1;
2309#endif // PIECEWISE_INTERPOLATION
2310 }
2311 check_values(
2312 proj_data_info_sptr, delta, cphi, sphi, s, ring0, X, Y, Z, ds, dz, num_planes_per_axial_pos, axial_pos_to_z_offset);
2313
2314 } while ((X * X + Y * Y <= image_rad * image_rad) && (Z <= maxplane || Q >= minplane));
2315}
2316
2317/****************************************************************************************/
2318
2319static Succeeded
2320find_start_values(const shared_ptr<const ProjDataInfoCylindricalArcCorr> proj_data_info_sptr,
2321 const float delta,
2322 const double cphi,
2323 const double sphi,
2324 const int s,
2325 const int ring0,
2326 const float image_rad,
2327 const double d_sl,
2328 int& X1,
2329 int& Y1,
2330 int& Z1,
2331 double& ds,
2332 double& dz,
2333 double& dzhor,
2334 double& dzvert,
2335 const float num_planes_per_axial_pos,
2336 const float axial_pos_to_z_offset)
2337{
2338 // use notations from Egger's thesis
2339
2340 const double d_p = proj_data_info_sptr->get_tangential_sampling();
2341 // d_xy = image.get_voxel_size().x, but we can use the bin_size here as
2342 // the routines.work only when these 2 are equal
2343 const double d_xy = proj_data_info_sptr->get_tangential_sampling();
2344
2345 const double R2 = square(proj_data_info_sptr->get_ring_radius());
2346 /* Radius of scanner squared in Pixel^2 */
2347 const double R2p = R2 / d_xy / d_xy;
2348
2349 // TODO REMOVE ASSUMPTION
2350 const int num_planes_per_physical_ring = 2;
2351 assert(fabs(d_sl * num_planes_per_physical_ring / proj_data_info_sptr->get_ring_spacing() - 1) < 10E-4);
2352
2353 /* KT 16/06/98
2354 This code should select a pixel inside the FOV.
2355 I tried to set rpix=image_rad, and
2356 X1 = (int)(X1f<0 ? ceil(X1f) : floor(X1f));
2357 Y1 = (int)(Y1f<0 ? ceil(Y1f) : floor(Y1f));
2358 Up to this point it is fine. However, it would also require (messy?)
2359 modifications of the 'push back into beam' code, so I gave up.
2360
2361 So, now we simply take rpix=image_rad-1. This means that sometimes a
2362 pixel close to the border is not selected.
2363 Not that anyone cares...
2364 */
2365 int rpix = round(image_rad - 1); /* Radius of target image in voxel units */
2366 const double r2 = rpix * rpix * d_xy * d_xy; /* Radius squared of target image in mm^2 */
2367
2368 // Formula in Eq 6.12 of Egger Matthias PhD
2369 // First compute X1, Y1
2370 // KT 16/06/98 added const
2371 const double t = s + 0.5; /* In a beam, not on a ray */
2372
2373 // KT 25/09/2001 replace assert() with return value
2374 // check if there is any pixel in the beam
2375 if (t > rpix)
2376 return Succeeded::no;
2377
2378 {
2379 const double root = sqrt(rpix * rpix - t * t); // Eq 6.12 in EGger Thesis
2380 const double X1f = t * cphi + sphi * root; /* Only valid if d_xy = d_p from Eq 6.12 in EGger Thesis */
2381 // const double X2f = t * cphi - sphi * root;
2382 const double Y1f = t * sphi - cphi * root; // Eq 6.12 in EGger Thesis
2383 // const double Y2f = t * sphi + cphi * root;
2384
2385 // KTTODO when using even number of bins, this should be floor(X1f) + .5
2386 X1 = (int)floor(X1f + 0.5);
2387 // X2 = (int) floor(X2f + 0.5);
2388 Y1 = (int)floor(Y1f + 0.5);
2389 // Y2 = (int) floor(Y2f + 0.5);
2390 }
2391
2392 // Compute ds = difference between s and s-projection of selected voxel
2393 // KT 22/05/98 we don't need t later on
2394 // t=X1*cphi+Y1*sphi;
2395 // ds=t-s;
2396 ds = X1 * cphi + Y1 * sphi - s; // Eq 6.13 in Egger thsis
2397 // Note that X1f*cphi+Y1f*sphi == t == s + 0.5, so
2398 // ds == (X1-X1f)*cphi + (Y1-Y1f)*sphi + 0.5, hence
2399 // -(cphi + sphi)/2 + 0.5 <= ds <= (cphi + sphi)/2 + 0.5
2400
2401 /* Push voxel back into beam */
2402 // KT 16/06/98 I now always use the cos(phi) case
2403 // For example, when ds<0, adding sin(phi) is not guaranteed to make it positive
2404 // (where the most obvious example was phi==0, although I did treat that correctly).
2405 // On the other hand ds + cphi >= (cphi-sphi)/2 + 0.5, which is >=0.5 as
2406 // 0<=phi<=45 (in fact, it is still >=0 if 45<phi<=90).
2407 // Similarly, ds - cphi <= -(cphi-sphi)/2 + 0.5 <= 1 for 0<=phi<=90.
2408
2409 if (ds < epsilon)
2410 {
2411#if 0
2412 if(sphi>epsilon)
2413 {
2414 Y1++;
2415 //Y2--;
2416 //t+=sphi;
2417 ds+=sphi;
2418 }
2419 else
2420#endif
2421 {
2422 X1++;
2423 // X2--;
2424 // t+=cphi;
2425 ds += cphi;
2426 // Now 0.5 <= (cphi-sphi)/2 + 0.5 <= ds < cphi+epsilon
2427 }
2428 }
2429 else if (ds >= 1.)
2430 {
2431#if 0
2432 if(sphi>epsilon)
2433 {
2434 Y1--;
2435 //Y2++;
2436 //t-=sphi;
2437 ds-=sphi;
2438 }
2439 else
2440#endif
2441 {
2442 X1--;
2443 // X2++;
2444 // t-=cphi;
2445 ds -= cphi;
2446 // Now 0 <= 1-cphi<= ds <= -(cphi-sphi)/2 + 0.5 <= 0.5
2447 }
2448 }
2449 // At the end of all this, 0 <= ds < 1
2450
2451 // Now find Z1
2452 // Note that t=s+.5
2453 {
2454 const double t2dp2 = t * t * d_p * d_p; // Eq 6.12 in EGger thesis
2455 // const double ttheta =(delta * d_sl / sqrt(R2 - t2dp2));//Equivalent to tan(theta) see Eq 6.10 in Egger thesis except that
2456 // d_r/2 has been replaced to d_sl
2457
2458 if (t2dp2 >= R2 || t2dp2 > r2)
2459 return Succeeded::no;
2460
2461 const double root1 = sqrt(R2 - t2dp2);
2462 const double root2 = sqrt(r2 - t2dp2);
2463
2464 // Eq 6.12 in Egger's thesis
2465 // const double Z1f = 2 * ring0 + 1 + (ttheta * (root1 - root2))/d_sl:
2466 // equivalent formula:
2467 // Z1f = 2 * ring0 + 1 + delta * (1 - root2/root1)
2468 // We convert this to 'general' sizes of planes w.r.t. rings
2469 // KT&CL 22/12/99 inserted offset
2470 const double Z1f = num_planes_per_axial_pos * (ring0 + 0.5) + axial_pos_to_z_offset
2471 + num_planes_per_physical_ring * delta / 2 * (1 - root2 / root1);
2472 // const double Z2f = (ring0 + 0.5)/ring_unit + (ttheta * (root1 + root2))/d_sl;
2473 // TODO possible problem for negative Z1f, use floor() instead
2474 Z1 = (int)floor(Z1f);
2475
2476 // Z2 = (int) Z2f;
2477 }
2478 {
2479
2480 // Compute 'z' (formula 6.15 in Egger's thesis) which is the ring coordinate of the
2481 // projection of the voxel X1,Y1,Z1
2482 const double root = sqrt(R2p - t * t); // CL 26/10/98 Put it back the original formula as before it was root=sqrt(R2p-s*s)
2483 // const double z=ring_unit*( Z1-delta*( (-X1*sphi+Y1*cphi)/root + 1 ) );// Eq 6.15 from Egger Thesis//CL SPAN 14/09/98
2484 // 2*delta
2485 // KT&CL 22/12/99 inserted offset
2486 const double z
2487 = (Z1 - num_planes_per_physical_ring * delta / 2 * ((-X1 * sphi + Y1 * cphi) / root + 1) - axial_pos_to_z_offset)
2488 / num_planes_per_axial_pos;
2489 dz = z - ring0;
2490 // Using the same formula (z=...) for X1f, Y1f, Z1f gives zf = ring0+ 0.5
2491 // As the difference between X1f, Y1f, Z1f and X1,Y1,Y2 is at most 1 in every coordinate,
2492 // -1/2 - delta/root/2 <= z - zf <= delta/root/2, so
2493 // -delta/root/2 <= dz <= 0.5 + delta/root/2
2494 // As delta < Rpix for most scanners, -1/num_planes_per_axial_pos < dz < 1
2495 // For some scanners though (e.g. HiDAC) this is not true, so we keep on checking if
2496 // dz is in the appropriate range
2497
2498 /* Push voxel back into beam */
2499 // KT 01/06/98 added 'else' here for the case when dz=1/num_planes_per_axial_pos, the first step puts it to 0,
2500 // the 2nd step shouldn't do anything (dz<0), but because we compare with epsilon,
2501 // it got back to .5
2502
2503 // MOREZ: if ->while
2504 if (dz >= 1. / num_planes_per_axial_pos)
2505 {
2506 while (dz >= 1. / num_planes_per_axial_pos)
2507 {
2508 Z1--;
2509 // z-=1/num_planes_per_axial_pos;
2510 dz -= 1. / num_planes_per_axial_pos;
2511 }
2512 }
2513 else // if
2514 {
2515 while (dz < epsilon)
2516 {
2517 Z1++;
2518 // z+=1/num_planes_per_axial_pos;
2519 dz += 1. / num_planes_per_axial_pos;
2520 }
2521 }
2522
2523 // TODO we could do a test of either Z or its Q lies in the axial FOV
2524 // if not, go along the beam. This could save us some updates of the
2525 // incremental quantities.
2526
2527 // KT&CL 22/12/99 changed ring_unit
2528 dzvert = -delta * cphi / root / num_planes_per_axial_pos; /* Only valid if d_xy = d_p */
2529 dzhor = -delta * sphi / root / num_planes_per_axial_pos;
2530 }
2531
2532 return Succeeded::yes;
2533}
2534
2535END_NAMESPACE_STIR
Declares class stir::BackProjectorByBinUsingInterpolation.
Declaration of class stir::ProjDataInfoCylindricalArcCorr.
Declaration of class stir::ProjDataInfo.
Declaration of class stir::Succeeded.
defines the stir::VoxelsOnCartesianGrid class
Declaration of stir::error()
void warning(const char *const s,...)
Print warning with format string a la printf.
Definition warning.cxx:41
NUMBER square(const NUMBER &x)
returns the square of a number, templated.
Definition common.h:154
int round(const float x)
Implements rounding of floating point numbers.
Definition round.inl:59
Declaration of the stir::round functions.
Declaration of stir::warning()