STIR 6.4.0
ProjDataInfoCylindrical.inl
Go to the documentation of this file.
1/*
2 Copyright (C) 2000 PARAPET partners
3 Copyright (C) 2000-2003, Hammersmith Imanet Ltd
4 Copyright (C) 2013, University College London
5 Copyright (C) 2013, Institute for Bioengineering of Catalonia
6 Copyright (C) 2018, University of Leeds
7
8 This file is part of STIR.
9
10 SPDX-License-Identifier: Apache-2.0 AND License-ref-PARAPET-license
11
12 See STIR/LICENSE.txt for details
13*/
27
28// for sqrt
29#include <math.h>
30#include "stir/Bin.h"
31#include "stir/Succeeded.h"
32#include "stir/is_null_ptr.h"
33#include "stir/error.h"
34#include <algorithm>
35
36START_NAMESPACE_STIR
37
38void
39ProjDataInfoCylindrical::initialise_ring_diff_arrays_if_not_done_yet() const
40{
41 // for efficiency reasons, use "Double-Checked-Locking(DCL) pattern" with OpenMP atomic operation
42 // OpenMP v3.1 or later required
43 // thanks to yohjp:
44 // http://stackoverflow.com/questions/27975737/how-to-handle-cached-data-structures-with-multi-threading-e-g-openmp
45#if defined(STIR_OPENMP) && _OPENMP >= 201012
46 bool initialised;
47# pragma omp atomic read
48 initialised = ring_diff_arrays_computed;
49
50 if (!initialised)
51#endif
52 {
53#if defined(STIR_OPENMP)
54# pragma omp critical(PROJDATAINFOCYLINDRICALRINGDIFFARRAY)
55#endif
56 {
57 if (!ring_diff_arrays_computed)
58 initialise_ring_diff_arrays();
59 }
60 }
61}
62
63// PW Added the view offset from the scanner, code may now support intrinsic tilt.
64float
66{
67 return bin.view_num() * azimuthal_angle_sampling + azimuthal_angle_offset;
68}
69
70float
72{
73
74 this->initialise_ring_diff_arrays_if_not_done_yet();
75 return bin.axial_pos_num() * get_axial_sampling(bin.segment_num()) - m_offset[bin.segment_num()];
76}
77
78float
80{
81 return get_m(bin) * get_costheta(bin);
82}
83
84float
86{
87 const float delta = get_average_ring_difference(bin.segment_num());
88 if (fabs(delta) < 0.0001F)
89 return 0;
90 const float R = get_ring_radius(bin.view_num());
91 assert(R >= fabs(get_s(bin)));
92 return delta * ring_spacing / (2 * sqrt(square(R) - square(get_s(bin))));
93}
94
95float
100
101float
106
107int
108ProjDataInfoCylindrical::get_num_axial_poss_per_ring_inc(const int segment_num) const
109{
110 return max_ring_diff[segment_num] != min_ring_diff[segment_num] ? 2 : 1;
111}
112
113float
115{
116 return azimuthal_angle_offset;
117}
118
119float
121{
122 return azimuthal_angle_sampling;
123}
124
125float
127{
128 return ring_spacing / get_num_axial_poss_per_ring_inc(segment_num);
129}
130
131float
133{
134 // KT 05/07/2001 use float division here.
135 // In any reasonable case, min+max_ring_diff will be even.
136 // But some day, an unreasonable case will walk in.
137 return (min_ring_diff[segment_num] + max_ring_diff[segment_num]) / 2.F;
138}
139
140int
142{
143 return min_ring_diff[segment_num];
144}
145
146int
148{
149 return max_ring_diff[segment_num];
150}
151
152float
154{
155 if (this->ring_radius.get_min_index() != 0 || this->ring_radius.get_max_index() != 0)
156 {
157 // check if all elements are equal
158 for (VectorWithOffset<float>::const_iterator iter = this->ring_radius.begin(); iter != this->ring_radius.end(); ++iter)
159 {
160 if (*iter != *this->ring_radius.begin())
161 error("get_ring_radius called for non-circular ring");
162 }
163 }
164 return *this->ring_radius.begin();
165}
166
167void
169{
170 if (new_ring_radius.get_min_index() != this->get_min_view_num() || new_ring_radius.get_max_index() != this->get_max_view_num())
171 {
172 error("error set_ring_radii_for_all_views: you need to use correct range of view numbers");
173 }
174
175 this->ring_radius = new_ring_radius;
176}
177
180{
181 if (this->ring_radius.get_min_index() == 0 && this->ring_radius.get_max_index() == 0)
182 {
184 out.fill(this->ring_radius[0]);
185 return out;
186 }
187 else
188 return this->ring_radius;
189}
190
191float
192ProjDataInfoCylindrical::get_ring_radius(const int view_num) const
193{
194 if (this->ring_radius.get_min_index() == 0 && this->ring_radius.get_max_index() == 0)
195 return ring_radius[0];
196 else
197 return ring_radius[view_num];
198}
199
200float
202{
203 return ring_spacing;
204}
205
206int
208{
209 // KT 10/05/2002 new assert
210 assert(get_scanner_ptr()->get_num_detectors_per_ring() > 0);
211 // KT 10/05/2002 moved assert here from constructor
212 assert(get_scanner_ptr()->get_num_detectors_per_ring() % (2 * get_num_views()) == 0);
213 // KT 28/11/2001 do not pre-store anymore as set_num_views would invalidate it
214 return get_scanner_ptr()->get_num_detectors_per_ring() / 2 / get_num_views();
215}
216
218ProjDataInfoCylindrical::get_segment_num_for_ring_difference(int& segment_num, const int ring_diff) const
219{
221 return Succeeded::no;
222
223 // check currently necessary as reduce_segment does not reduce the size of the ring_diff arrays
225 return Succeeded::no;
226
227 this->initialise_ring_diff_arrays_if_not_done_yet();
228
229 segment_num = ring_diff_to_segment_num[ring_diff];
230 // warning: relies on initialise_ring_diff_arrays to set invalid ring_diff to a too large segment_num
231 if (segment_num <= get_max_segment_num())
232 return Succeeded::yes;
233 else
234 return Succeeded::no;
235}
236
239 int& ax_pos_num,
240 const int ring1,
241 const int ring2) const
242{
243 assert(0 <= ring1);
244 assert(ring1 < get_scanner_ptr()->get_num_rings());
245 assert(0 <= ring2);
246 assert(ring2 < get_scanner_ptr()->get_num_rings());
247
248 // KT 01/08/2002 swapped rings
249 if (get_segment_num_for_ring_difference(segment_num, ring2 - ring1) == Succeeded::no)
250 return Succeeded::no;
251
252 // see initialise_ring_diff_arrays() for some info
253 ax_pos_num = (ring1 + ring2 - ax_pos_num_offset[segment_num]) * get_num_axial_poss_per_ring_inc(segment_num) / 2;
254 return Succeeded::yes;
255}
256
258ProjDataInfoCylindrical::get_all_ring_pairs_for_segment_axial_pos_num(const int segment_num, const int axial_pos_num) const
259{
260 this->initialise_ring_diff_arrays_if_not_done_yet();
261 return *this->segment_axial_pos_to_ring_pair[segment_num][axial_pos_num];
262}
263
264unsigned
265ProjDataInfoCylindrical::get_num_ring_pairs_for_segment_axial_pos_num(const int segment_num, const int axial_pos_num) const
266{
267 return static_cast<unsigned>(this->get_all_ring_pairs_for_segment_axial_pos_num(segment_num, axial_pos_num).size());
268}
269
270END_NAMESPACE_STIR
Declaration of class stir::Bin.
Declaration of class stir::Succeeded.
A class for storing coordinates and value of a single projection bin.
Definition Bin.h:49
int axial_pos_num() const
get axial position number
Definition Bin.inl:70
float get_phi(const Bin &) const override
Get azimuthal angle phi of the normal to the projection plane.
Definition ProjDataInfoCylindrical.inl:65
std::vector< std::pair< int, int > > RingNumPairs
Type used by get_all_ring_pairs_for_segment_axial_pos_num()
Definition ProjDataInfoCylindrical.h:56
virtual VectorWithOffset< float > get_ring_radii_for_all_views() const
Get detector ring radius for all views.
Definition ProjDataInfoCylindrical.inl:179
virtual float get_azimuthal_angle_offset() const
Get azimuthal angle offset (in radians)
Definition ProjDataInfoCylindrical.inl:114
const RingNumPairs & get_all_ring_pairs_for_segment_axial_pos_num(const int segment_num, const int axial_pos_num) const
Find all ring pairs that contribute to a segment and axial position.
Definition ProjDataInfoCylindrical.inl:258
virtual float get_ring_radius() const
Get detector ring radius.
Definition ProjDataInfoCylindrical.inl:153
virtual float get_ring_spacing() const
Get detector ring spacing.
Definition ProjDataInfoCylindrical.inl:201
float get_sampling_in_t(const Bin &) const override
Get sampling distance in the t coordinate.
Definition ProjDataInfoCylindrical.inl:102
virtual void set_ring_radii_for_all_views(const VectorWithOffset< float > &new_ring_radius)
Set detector ring radius for all views.
Definition ProjDataInfoCylindrical.inl:168
Succeeded get_segment_num_for_ring_difference(int &segment_num, const int ring_diff) const
Find which segment a particular ring difference belongs to.
Definition ProjDataInfoCylindrical.inl:218
float get_tantheta(const Bin &) const override
Get tangent of the co-polar angle of the normal to the projection plane.
Definition ProjDataInfoCylindrical.inl:85
virtual float get_azimuthal_angle_sampling() const
Get the azimuthal sampling (in radians)
Definition ProjDataInfoCylindrical.inl:120
unsigned get_num_ring_pairs_for_segment_axial_pos_num(const int segment_num, const int axial_pos_num) const
Find the number of ring pairs that contribute to a segment and axial position.
Definition ProjDataInfoCylindrical.inl:265
float get_t(const Bin &) const override
Get value of the (roughly) axial coordinate in the projection plane (in mm)
Definition ProjDataInfoCylindrical.inl:79
virtual int get_view_mashing_factor() const
Get the mashing factor, i.e. how many 'original' views are combined.
Definition ProjDataInfoCylindrical.inl:207
virtual float get_axial_sampling(int segment_num) const
Get the axial sampling (e.g in z_direction)
Definition ProjDataInfoCylindrical.inl:126
float get_sampling_in_m(const Bin &) const override
Get sampling distance in the m coordinate.
Definition ProjDataInfoCylindrical.inl:96
int get_min_ring_difference(int segment_num) const
Get minimum ring difference for the given segment.
Definition ProjDataInfoCylindrical.inl:141
Succeeded get_segment_axial_pos_num_for_ring_pair(int &segment_num, int &axial_pos_num, const int ring1, const int ring2) const
Find to which segment and axial position a ring pair contributes.
Definition ProjDataInfoCylindrical.inl:238
float get_m(const Bin &) const override
Return z-coordinate of the middle of the LOR.
Definition ProjDataInfoCylindrical.inl:71
bool sampling_corresponds_to_physical_rings
a variable that is set if the data corresponds to physical rings in the scanner
Definition ProjDataInfoCylindrical.h:275
int get_max_ring_difference(int segment_num) const
Get maximum ring difference for the given segment.
Definition ProjDataInfoCylindrical.inl:147
float get_average_ring_difference(int segment_num) const
Get average ring difference for the given segment.
Definition ProjDataInfoCylindrical.inl:132
int get_num_views() const
Get number of views.
Definition ProjDataInfo.inl:59
int get_min_segment_num() const
Get minimum segment number.
Definition ProjDataInfo.inl:120
float get_costheta(const Bin &) const
Get cosine of the co-polar angle of the normal to the projection plane.
Definition ProjDataInfo.inl:200
int get_min_view_num() const
Get minimum view number.
Definition ProjDataInfo.inl:144
int get_max_view_num() const
Get maximum view number.
Definition ProjDataInfo.inl:150
const Scanner * get_scanner_ptr() const
Get scanner pointer.
Definition ProjDataInfo.inl:212
virtual float get_s(const Bin &) const =0
Get value of the tangential coordinate in the projection plane (in mm)
int get_max_segment_num() const
Get maximum segment number.
Definition ProjDataInfo.inl:126
int segment_num() const
get segment number for const objects
Definition SegmentIndices.inl:32
a class containing an enumeration type that can be used by functions to signal successful operation o...
Definition Succeeded.h:44
A templated class for vectors, but with indices starting not from 0.
Definition VectorWithOffset.h:65
int get_max_index() const
get value of last valid index
Definition VectorWithOffset.inl:131
int get_min_index() const
get value of first valid index
Definition VectorWithOffset.inl:124
void fill(const T &n)
fill elements with value n
Definition VectorWithOffset.inl:571
int view_num() const
get view number for const objects
Definition ViewgramIndices.inl:36
Declaration of stir::error()
void error(const char *const s,...)
Print error with format string a la printf and throw exception.
Definition error.cxx:42
NUMBER square(const NUMBER &x)
returns the square of a number, templated.
Definition common.h:154
Definition of stir::is_null_ptr functions.