STIR 6.5.0
line_distances.h
Go to the documentation of this file.
1//
2//
3
12/*
13 Copyright (C) 2005- 2005, Hammersmith Imanet Ltd
14 Copyright (C) 2016, University of Hull
15
16 This file is part of STIR.
17
18 SPDX-License-Identifier: Apache-2.0
19
20 See STIR/LICENSE.txt for details.
21*/
22#ifndef __stir_geometry_line_distances_H__
23#define __stir_geometry_line_distances_H__
24
26#include "stir/LORCoordinates.h"
27#include <cmath>
28#ifdef BOOST_NO_STDC_NAMESPACE
29namespace std
30{
31using ::sqrt;
32using ::fabs;
33} // namespace std
34#endif
35
36START_NAMESPACE_STIR
37
46template <class coordT>
47inline coordT
49 const LORAs2Points<coordT>& line0,
50 const LORAs2Points<coordT>& line1)
51{
52 /* Rationale:
53 parametrise points on the lines as
54 r0 + a0 d0, r1 + a1 d1
55 where r0 is a point on the line, and d0 is its direction
56
57 compute distance squared between those points, i.e.
58 norm(a0 d0 - a1 d1 + r0-r1)^2
59 This can be written using inner products of all the vectors.
60
61 Minimising it (by computing derivatives) results in a linear eq in a0, a1:
62 a0 d0d0 == a1 d0d1 + r10d0,
63 a0 d0d1 == a1 d1d1 + r10d1
64 which is easily solved.
65 The half-way point can then be found by using
66 (r0 + a0 d0 + r1 + a1 d1)/2
67 for the a0,a1 found.
68 */
69 const CartesianCoordinate3D<coordT>& r0 = line0.p1();
70 const CartesianCoordinate3D<coordT>& r1 = line1.p1();
71 const CartesianCoordinate3D<coordT> r10 = r1 - r0;
72 const CartesianCoordinate3D<coordT> d0 = line0.p2() - line0.p1();
73 const CartesianCoordinate3D<coordT> d1 = line1.p2() - line1.p1();
74 const coordT d0d0 = inner_product(d0, d0);
75 const coordT d0d1 = inner_product(d0, d1);
76 const coordT d1d1 = inner_product(d1, d1);
77 const coordT r10d0 = inner_product(r10, d0);
78 const coordT r10r10 = inner_product(r10, r10);
79
80 const coordT eps = d0d0 * 10E-5; // small number for comparisons
81
82 const coordT denom = square(d0d1) - d0d0 * d1d1;
83 coordT distance_squared;
84 if (std::fabs(denom) <= eps)
85 {
86 // parallel lines
87 const coordT a0 = r10d0 / d0d0;
88 result = r0 + d0 * a0;
89 distance_squared = r10r10 - square(r10d0) / d0d0;
90 }
91 else
92 {
93 const coordT r10d1 = inner_product(r10, d1);
94 const coordT a0 = (-d1d1 * r10d0 + d0d1 * r10d1) / denom;
95 const coordT a1 = (-d0d1 * r10d0 + d0d0 * r10d1) / denom;
96
97 result = ((r0 + d0 * a0) + (r1 + d1 * a1)) / 2;
98 distance_squared = (d1d1 * square(r10d0) - 2 * d0d1 * r10d0 * r10d1 + d0d0 * square(r10d1)) / denom + r10r10;
99 }
100 if (distance_squared >= 0)
101 return std::sqrt(distance_squared);
102 else
103 {
104 if (-distance_squared < eps)
105 return 0;
106 else
107 {
108 assert(false);
109 return std::sqrt(distance_squared); // will return NaN
110 }
111 }
112}
113
118template <class coordT>
119inline coordT
121{
122 /* Rationale:
123 parametrise points on the lines as
124 r0 + a0 d0
125 where r0 is a point on the line, and d0 is its direction
126
127 compute distance squared between those points, i.e.
128 norm(a0 d0 + r0-r1)^2
129 This can be written using inner products of all the vectors:
130 a0^2 d0d0 - 2 a0 r10d0 + r10r10
131 Minimising it (by computing derivatives) results in a linear eq in a0, a1:
132 a0 d0d0 == r10d0
133 */
134 const CartesianCoordinate3D<coordT>& r0 = line.p1();
135 const CartesianCoordinate3D<coordT> r10 = r1 - r0;
136 const CartesianCoordinate3D<coordT> d0 = line.p2() - line.p1();
137 const coordT d0d0 = inner_product(d0, d0);
138 const coordT r10d0 = inner_product(r10, d0);
139 const coordT r10r10 = inner_product(r10, r10);
140
141 // const coordT a0 = r10d0/d0d0;
142 // result = r0 + d0*a0;
143 const coordT distance_squared = r10r10 - square(r10d0) / d0d0;
144 if (distance_squared >= 0)
145 return std::sqrt(distance_squared);
146 else
147 {
148 if (-distance_squared < d0d0 * 10E-5)
149 return 0;
150 else
151 {
152 assert(false);
153 return std::sqrt(distance_squared); // will return NaN
154 }
155 }
156}
157
163template <class coordT>
164inline void
168{
169
170 const CartesianCoordinate3D<coordT> difference = p2 - p1;
171
172 const CartesianCoordinate3D<coordT> r10 = r1 - p1;
173
174 float inner_prod = inner_product(difference, difference);
175
176 const float u = inner_product(r10, difference) / inner_prod;
177
178 r1.x() = p1.x() + u * difference.x();
179 r1.y() = p1.y() + u * difference.y();
180 r1.z() = p1.z() + u * difference.z();
181}
182
183END_NAMESPACE_STIR
184
185#endif
defines the stir::CartesianCoordinate3D<coordT> class
defines various classes for specifying a line in 3 dimensions
a templated class for 3-dimensional coordinates.
Definition CartesianCoordinate3D.h:53
A class for LORs.
Definition LORCoordinates.h:296
coordT inner_product(const BasicCoordinate< num_dimensions, coordT > &p1, const BasicCoordinate< num_dimensions, coordT > &p2)
compute sum_i p1[i] * p2[i]
Definition BasicCoordinate.inl:408
NUMBER square(const NUMBER &x)
returns the square of a number, templated.
Definition common.h:154
coordT coordinate_between_2_lines(CartesianCoordinate3D< coordT > &result, const LORAs2Points< coordT > &line0, const LORAs2Points< coordT > &line1)
find a point half-way between 2 lines and their distance
Definition line_distances.h:48
coordT distance_between_line_and_point(const LORAs2Points< coordT > &line, const CartesianCoordinate3D< coordT > &r1)
find the distance between a point and a line
Definition line_distances.h:120
void project_point_on_a_line(const CartesianCoordinate3D< coordT > &p1, const CartesianCoordinate3D< coordT > &p2, CartesianCoordinate3D< coordT > &r1)
Project a point on a line.
Definition line_distances.h:165