STIR 6.4.0
LORCoordinates.h
Go to the documentation of this file.
1//
2//
3#ifndef __stir_LORCoordinates_H__
4#define __stir_LORCoordinates_H__
5
16/*
17 Copyright (C) 2004 - 2009-06-22, Hammersmith Imanet Ltd
18 Copyright (C) 2011-07-01 - 2013, Kris Thielemans
19 Copyright 2017 ETH Zurich, Institute of Particle Physics and Astrophysics
20 This file is part of STIR.
21
22 SPDX-License-Identifier: Apache-2.0
23
24 See STIR/LICENSE.txt for details
25*/
26
28#include "stir/Succeeded.h"
29
30START_NAMESPACE_STIR
31
32// predeclarations to allow cross-referencing
33template <class coordT>
34class LOR;
35template <class coordT>
36class LORInAxialAndSinogramCoordinates;
37template <class coordT>
38class LORInCylinderCoordinates;
39template <class coordT>
40class LORInAxialAndNoArcCorrSinogramCoordinates;
41template <class coordT>
42class LORAs2Points;
43
57template <class coordT>
58class LOR
59{
60public:
61 virtual ~LOR() {}
62
63 virtual LOR* clone() const = 0;
64
66 virtual bool is_swapped() const = 0;
67
68 virtual Succeeded change_representation(LORInCylinderCoordinates<coordT>&, const double radius) const = 0;
69 virtual Succeeded change_representation(LORInAxialAndNoArcCorrSinogramCoordinates<coordT>&, const double radius) const = 0;
70 virtual Succeeded change_representation(LORInAxialAndSinogramCoordinates<coordT>&, const double radius) const = 0;
71 virtual Succeeded get_intersections_with_cylinder(LORAs2Points<coordT>&, const double radius) const = 0;
72};
73
78
79template <class coordT>
80class PointOnCylinder
81{
82private:
83 // sorry: has to be first to give the compiler a better chance of inlining
84 void check_state() const
85 {
86 assert(0 <= _psi);
87 assert(_psi < static_cast<coordT>(2 * _PI));
88 }
89
90public:
91 coordT psi() const
92 {
93 check_state();
94 return _psi;
95 }
96 coordT& psi()
97 {
98 check_state();
99 return _psi;
100 }
101 coordT z() const { return _z; }
102 coordT& z() { return _z; }
103
104 inline PointOnCylinder();
105 inline PointOnCylinder(const coordT z, const coordT psi);
106
107private:
108 coordT _z;
109 coordT _psi;
110};
111
116template <class coordT>
117class LORCylindricalCoordinates_z_and_radius
118{
119private:
120 // sorry: has to be first to give the compiler a better chance of inlining
121 void check_state() const { assert(_radius > 0); }
122
123protected:
124 explicit LORCylindricalCoordinates_z_and_radius(coordT radius = 1)
125 : _radius(radius)
126 {
127 check_state();
128 }
129 LORCylindricalCoordinates_z_and_radius(coordT z1, coordT z2, coordT radius)
130 : _radius(radius),
131 _z1(z1),
132 _z2(z2)
133 {
134 check_state();
135 }
136
137 coordT z1() const
138 {
139 check_state();
140 return _z1;
141 }
142 coordT& z1()
143 {
144 check_state();
145 return _z1;
146 }
147 coordT z2() const
148 {
149 check_state();
150 return _z2;
151 }
152 coordT& z2()
153 {
154 check_state();
155 return _z2;
156 }
157
158 coordT radius() const
159 {
160 check_state();
161 return _radius;
162 }
163
164 inline void set_radius_no_check(const coordT new_radius)
165 {
166 check_state();
167 assert(new_radius > 0);
168 _z1 *= new_radius / _radius;
169 _z2 *= new_radius / _radius;
170 _radius = new_radius;
171 }
172 coordT _radius;
173
174protected:
175 coordT _z1;
176 coordT _z2;
177};
178
183template <class coordT>
184class LORInCylinderCoordinates : public LOR<coordT>
185{
186#ifdef STIR_COMPILING_SWIG_WRAPPER
187 // SWIG needs this typedef to be public
188public:
189#endif
190 typedef LORInCylinderCoordinates<coordT> self_type;
191
192private:
193 void check_state() const
194 {
195 assert(_radius > 0);
196 }
197
198public:
199 const PointOnCylinder<coordT>& p1() const
200 {
201 return _p1;
202 }
204 {
205 return _p1;
206 }
207 const PointOnCylinder<coordT>& p2() const
208 {
209 return _p2;
210 }
212 {
213 return _p2;
214 }
215
217
220 bool is_swapped() const override
221 {
222 return false;
223 }
224 void reset(coordT radius = 1)
225 {
226 // set psi such that the new LOR does intersect that cylinder
227 _p1.psi() = 0;
228 _p2.psi() = static_cast<coordT>(_PI);
229 _radius = radius;
230 }
231 coordT radius() const
232 {
233 check_state();
234 return _radius;
235 }
236
241 inline Succeeded set_radius(coordT new_radius)
242 {
243 check_state();
244 assert(new_radius > 0);
245 if (_radius == new_radius)
246 return Succeeded::yes;
247 // find minimum radius of a cylinder that is intersected by this LOR
248 const coordT min_radius = _radius * fabs(cos((_p1.psi() - _p2.psi()) / 2));
249 if (new_radius >= min_radius)
250 return Succeeded::no;
251 _p1.z() *= new_radius / _radius;
252 _p2.z() *= new_radius / _radius;
253 _radius = new_radius;
254 return Succeeded::yes;
255 }
256
257 inline explicit LORInCylinderCoordinates(const coordT radius = 1);
258
259 inline LORInCylinderCoordinates(const PointOnCylinder<coordT>& p1, const PointOnCylinder<coordT>& p2, const coordT radius = 1);
260
262
264
265#if 0
266 // disabled as would need radius argument as well, but currently not needed
267 inline
269#endif
270
271 self_type* clone() const override
272 {
273 return new self_type(*this);
274 }
275
276 Succeeded change_representation(LORInCylinderCoordinates<coordT>&, const double radius) const override;
277
278 Succeeded change_representation(LORInAxialAndNoArcCorrSinogramCoordinates<coordT>&, const double radius) const override;
279
280 Succeeded change_representation(LORInAxialAndSinogramCoordinates<coordT>&, const double radius) const override;
281
282 Succeeded get_intersections_with_cylinder(LORAs2Points<coordT>&, const double radius) const override;
283
284private:
285 PointOnCylinder<coordT> _p1;
286 PointOnCylinder<coordT> _p2;
287 coordT _radius;
288};
289
294template <class coordT>
295class LORAs2Points : public LOR<coordT>
296{
297#ifdef STIR_COMPILING_SWIG_WRAPPER
298 // SWIG needs this typedef to be public
299public:
300#endif
301 typedef LORAs2Points<coordT> self_type;
302
303public:
304 const CartesianCoordinate3D<coordT>& p1() const
305 {
306 return _p1;
307 }
309 {
310 return _p1;
311 }
312 const CartesianCoordinate3D<coordT>& p2() const
313 {
314 return _p2;
315 }
317 {
318 return _p2;
319 }
320
321 inline LORAs2Points();
322
323 inline LORAs2Points(const CartesianCoordinate3D<coordT>& p1, const CartesianCoordinate3D<coordT>& p2);
324
325 inline LORAs2Points(const LORInCylinderCoordinates<coordT>& cyl_coords);
326
327 inline LORAs2Points(const LORInAxialAndSinogramCoordinates<coordT>&);
328
329 inline LORAs2Points(const LORInAxialAndNoArcCorrSinogramCoordinates<coordT>&);
330
332
335 bool is_swapped() const override
336 {
337 return false;
338 }
339
340 self_type* clone() const override
341 {
342 return new self_type(*this);
343 }
344
345 Succeeded change_representation(LORInCylinderCoordinates<coordT>&, const double radius) const override;
346
347 Succeeded change_representation(LORInAxialAndNoArcCorrSinogramCoordinates<coordT>&, const double radius) const override;
348
349 Succeeded change_representation(LORInAxialAndSinogramCoordinates<coordT>&, const double radius) const override;
350
351 Succeeded get_intersections_with_cylinder(LORAs2Points<coordT>&, const double radius) const override;
352
354 Succeeded change_representation_for_block(LORInAxialAndNoArcCorrSinogramCoordinates<coordT>&, const double radius) const;
355
356private:
357 CartesianCoordinate3D<coordT> _p1;
358 CartesianCoordinate3D<coordT> _p2;
359};
360
365template <class coordT>
366class LORInAxialAndSinogramCoordinates : public LOR<coordT>, private LORCylindricalCoordinates_z_and_radius<coordT>
367{
368private:
369#ifdef STIR_COMPILING_SWIG_WRAPPER
370 // SWIG needs this typedef to be public
371public:
372#endif
373 typedef LORInAxialAndSinogramCoordinates<coordT> self_type;
374
375private:
376 typedef LORCylindricalCoordinates_z_and_radius<coordT> private_base_type;
377 // sorry: has to be first to give the compiler a better chance of inlining
378 void check_state() const
379 {
380 assert(private_base_type::_radius > 0);
381 assert(_s > -private_base_type::_radius);
382 assert(_s < private_base_type::_radius);
383 assert(_phi < static_cast<coordT>(_PI));
384 assert(_phi >= 0);
385 }
386
387public:
388 coordT z1() const
389 {
390 check_state();
391 return private_base_type::z1();
392 }
393 coordT& z1()
394 {
395 check_state();
396 return private_base_type::z1();
397 }
398 coordT z2() const
399 {
400 check_state();
401 return private_base_type::z2();
402 }
403 coordT& z2()
404 {
405 check_state();
406 return private_base_type::z2();
407 }
408 coordT phi() const
409 {
410 check_state();
411 return _phi;
412 }
413 coordT& phi()
414 {
415 check_state();
416 return _phi;
417 }
418 coordT s() const
419 {
420 check_state();
421 return _s;
422 }
423 coordT& s()
424 {
425 check_state();
426 return _s;
427 }
428
429 coordT beta() const
430 {
431 check_state();
432 return asin(_s / private_base_type::_radius);
433 }
434 bool is_swapped() const override
435 {
436 check_state();
437 return _swapped;
438 }
439 bool is_swapped()
440 {
441 check_state();
442 return _swapped;
443 }
444 inline explicit LORInAxialAndSinogramCoordinates(const coordT radius = 1);
445
447
451 inline LORInAxialAndSinogramCoordinates(
452 const coordT z1, const coordT z2, const coordT phi, const coordT s, const coordT radius = 1, const bool swapped = false);
453
454 inline LORInAxialAndSinogramCoordinates(const LORInCylinderCoordinates<coordT>&);
455
456 inline LORInAxialAndSinogramCoordinates(const LORInAxialAndNoArcCorrSinogramCoordinates<coordT>&);
457
458#if 0
459 inline
460 LORInAxialAndSinogramCoordinates(const LORAs2Points<coordT>&);
461#endif
462
463 self_type* clone() const override
464 {
465 return new self_type(*this);
466 }
467
468 void reset(coordT radius = 1)
469 {
470 // set such that the new LOR does intersect that cylinder
471 _s = 0;
472 private_base_type::_radius = radius;
473 }
474 coordT radius() const
475 {
476 check_state();
477 return private_base_type::_radius;
478 }
479
480 inline Succeeded set_radius(const coordT new_radius)
481 {
482 if (private_base_type::_radius == new_radius)
483 return Succeeded::yes;
484 assert(new_radius > 0);
485 if (fabs(s()) >= new_radius)
486 return Succeeded::no;
487 this->set_radius_no_check(new_radius);
488 return Succeeded::yes;
489 }
490
491 Succeeded change_representation(LORInCylinderCoordinates<coordT>&, const double radius) const override;
492
493 Succeeded change_representation(LORInAxialAndNoArcCorrSinogramCoordinates<coordT>&, const double radius) const override;
494
495 Succeeded change_representation(LORInAxialAndSinogramCoordinates<coordT>&, const double radius) const override;
496
497 Succeeded get_intersections_with_cylinder(LORAs2Points<coordT>&, const double radius) const override;
498
499private:
500 coordT _phi;
501 coordT _s;
502 bool _swapped;
503};
504
509template <class coordT>
510class LORInAxialAndNoArcCorrSinogramCoordinates : public LOR<coordT>, private LORCylindricalCoordinates_z_and_radius<coordT>
511{
512private:
513#ifdef STIR_COMPILING_SWIG_WRAPPER
514 // SWIG needs this typedef to be public
515public:
516#endif
517 typedef LORInAxialAndNoArcCorrSinogramCoordinates<coordT> self_type;
518 typedef LORCylindricalCoordinates_z_and_radius<coordT> private_base_type;
519
520 // sorry: has to be first to give the compiler a better chance of inlining
521 void check_state() const
522 {
523 assert(private_base_type::_radius > 0);
524 assert(_beta >= static_cast<coordT>(-_PI / 2));
525 assert(_beta < static_cast<coordT>(_PI / 2));
526 assert(_phi < static_cast<coordT>(_PI));
527 assert(_phi >= 0);
528 }
529
530public:
531 coordT z1() const
532 {
533 check_state();
534 return private_base_type::z1();
535 }
536 coordT& z1()
537 {
538 check_state();
539 return private_base_type::z1();
540 }
541 coordT z2() const
542 {
543 check_state();
544 return private_base_type::z2();
545 }
546 coordT& z2()
547 {
548 check_state();
549 return private_base_type::z2();
550 }
551 coordT phi() const
552 {
553 check_state();
554 return _phi;
555 }
556 coordT& phi()
557 {
558 check_state();
559 return _phi;
560 }
561 coordT beta() const
562 {
563 check_state();
564 return _beta;
565 }
566 coordT& beta()
567 {
568 check_state();
569 return _beta;
570 }
571 bool is_swapped() const override
572 {
573 check_state();
574 return _swapped;
575 }
576 bool is_swapped()
577 {
578 check_state();
579 return _swapped;
580 }
581
582 coordT s() const
583 {
584 check_state();
585 return private_base_type::_radius * sin(_beta);
586 }
587
588 void reset(coordT radius = 1)
589 {
590 // set such that the new LOR does intersect that cylinder
591 _beta = 0;
592 private_base_type::_radius = radius;
593 }
594 coordT radius() const
595 {
596 check_state();
597 return private_base_type::_radius;
598 }
599
600 inline Succeeded set_radius(const coordT new_radius)
601 {
602 if (private_base_type::_radius == new_radius)
603 return Succeeded::yes;
604 assert(new_radius > 0);
605 if (fabs(s()) >= new_radius)
606 return Succeeded::no;
607 this->set_radius_no_check(new_radius);
608 return Succeeded::yes;
609 }
610
611 inline explicit LORInAxialAndNoArcCorrSinogramCoordinates(const coordT radius = 1);
612
614
618 inline LORInAxialAndNoArcCorrSinogramCoordinates(
619 const coordT z1, const coordT z2, const coordT phi, const coordT beta, const coordT radius = 1, const bool swapped = false);
620
621 inline LORInAxialAndNoArcCorrSinogramCoordinates(const LORInCylinderCoordinates<coordT>&);
622
623 inline LORInAxialAndNoArcCorrSinogramCoordinates(const LORInAxialAndSinogramCoordinates<coordT>&);
624
625#if 0
626 inline
627 LORInAxialAndNoArcCorrSinogramCoordinates(const LORAs2Points<coordT>&);
628#endif
629
630 self_type* clone() const override
631 {
632 return new self_type(*this);
633 }
634
635 Succeeded change_representation(LORInCylinderCoordinates<coordT>&, const double radius) const override;
636
637 Succeeded change_representation(LORInAxialAndNoArcCorrSinogramCoordinates<coordT>&, const double radius) const override;
638
639 Succeeded change_representation(LORInAxialAndSinogramCoordinates<coordT>&, const double radius) const override;
640
641 Succeeded get_intersections_with_cylinder(LORAs2Points<coordT>&, const double radius) const override;
642
643private:
644 coordT _phi;
645 coordT _beta;
646 bool _swapped;
647};
648
653
654template <class coordT1, class coordT2>
655inline Succeeded
656find_LOR_intersections_with_cylinder(LORInCylinderCoordinates<coordT1>&, const LORAs2Points<coordT2>&, const double radius);
661template <class coordT1, class coordT2>
662inline Succeeded find_LOR_intersections_with_cylinder(LORAs2Points<coordT1>& intersection_coords,
663 const LORAs2Points<coordT2>& coords,
664 const double radius);
669template <class coordT1, class coordT2>
670inline Succeeded find_LOR_intersections_with_cylinder(LORInAxialAndNoArcCorrSinogramCoordinates<coordT1>& lor,
671 const LORAs2Points<coordT2>& cart_coords,
672 const double radius);
673
678template <class coordT1, class coordT2>
679inline Succeeded find_LOR_intersections_with_cylinder(LORInAxialAndSinogramCoordinates<coordT1>& lor,
680 const LORAs2Points<coordT2>& cart_coords,
681 const double radius);
682
683END_NAMESPACE_STIR
684
686
687#endif
defines the stir::CartesianCoordinate3D<coordT> class
Implementations for LORCoordinates.h.
Declaration of class stir::Succeeded.
a templated class for 3-dimensional coordinates.
Definition CartesianCoordinate3D.h:53
A class for LORs.
Definition LORCoordinates.h:296
bool is_swapped() const override
Return if the LOR direction is opposite from normal.
Definition LORCoordinates.h:335
A class for LORs.
Definition LORCoordinates.h:511
bool is_swapped() const override
Return if the LOR direction is opposite from normal.
Definition LORCoordinates.h:571
A class for LORs.
Definition LORCoordinates.h:367
bool is_swapped() const override
Return if the LOR direction is opposite from normal.
Definition LORCoordinates.h:434
A class for LORs.
Definition LORCoordinates.h:185
bool is_swapped() const override
Return if the LOR direction is opposite from normal.
Definition LORCoordinates.h:220
A base class for specifying an LOR with geometric coordinates.
Definition LORCoordinates.h:59
virtual bool is_swapped() const =0
Return if the LOR direction is opposite from normal.
A class for a point on a cylinder.
Definition LORCoordinates.h:81
a class containing an enumeration type that can be used by functions to signal successful operation o...
Definition Succeeded.h:44
Succeeded set_radius(coordT new_radius)
Changes the radius of the LOR.
Definition LORCoordinates.h:241
Succeeded find_LOR_intersections_with_cylinder(LORInCylinderCoordinates< coordT1 > &, const LORAs2Points< coordT2 > &, const double radius)
Given an LOR, find its intersection with a (infintely long) cylinder.
Definition LORCoordinates.inl:357
#define _PI
The constant pi to high precision.
Definition common.h:141