comparison Framework/Volumes/VolumeImageGeometry.cpp @ 742:fa5febe0f0c2

moved OrientedBoundingBox in the Volumes folder
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 22 May 2019 09:41:03 +0200
parents Framework/Toolbox/VolumeImageGeometry.cpp@93a8949a1ef7
children e8fdf29cd0ca
comparison
equal deleted inserted replaced
741:c1d6a566dfd3 742:fa5febe0f0c2
1 /**
2 * Stone of Orthanc
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2019 Osimis S.A., Belgium
6 *
7 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU Affero General Public License
9 * as published by the Free Software Foundation, either version 3 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/
20
21
22 #include "VolumeImageGeometry.h"
23
24 #include "../Toolbox/GeometryToolbox.h"
25
26 #include <Core/OrthancException.h>
27
28
29 namespace OrthancStone
30 {
31 void VolumeImageGeometry::Invalidate()
32 {
33 Vector p = (axialGeometry_.GetOrigin() +
34 static_cast<double>(depth_ - 1) * voxelDimensions_[2] * axialGeometry_.GetNormal());
35
36 coronalGeometry_ = CoordinateSystem3D(p,
37 axialGeometry_.GetAxisX(),
38 -axialGeometry_.GetNormal());
39
40 sagittalGeometry_ = CoordinateSystem3D(p,
41 axialGeometry_.GetAxisY(),
42 axialGeometry_.GetNormal());
43
44 Vector origin = (
45 axialGeometry_.MapSliceToWorldCoordinates(-0.5 * voxelDimensions_[0],
46 -0.5 * voxelDimensions_[1]) -
47 0.5 * voxelDimensions_[2] * axialGeometry_.GetNormal());
48
49 Vector scaling;
50
51 if (width_ == 0 ||
52 height_ == 0 ||
53 depth_ == 0)
54 {
55 LinearAlgebra::AssignVector(scaling, 1, 1, 1);
56 }
57 else
58 {
59 scaling = (
60 axialGeometry_.GetAxisX() * voxelDimensions_[0] * static_cast<double>(width_) +
61 axialGeometry_.GetAxisY() * voxelDimensions_[1] * static_cast<double>(height_) +
62 axialGeometry_.GetNormal() * voxelDimensions_[2] * static_cast<double>(depth_));
63 }
64
65 transform_ = LinearAlgebra::Product(
66 GeometryToolbox::CreateTranslationMatrix(origin[0], origin[1], origin[2]),
67 GeometryToolbox::CreateScalingMatrix(scaling[0], scaling[1], scaling[2]));
68
69 LinearAlgebra::InvertMatrix(transformInverse_, transform_);
70 }
71
72
73 VolumeImageGeometry::VolumeImageGeometry() :
74 width_(0),
75 height_(0),
76 depth_(0)
77 {
78 LinearAlgebra::AssignVector(voxelDimensions_, 1, 1, 1);
79 Invalidate();
80 }
81
82
83 void VolumeImageGeometry::SetSize(unsigned int width,
84 unsigned int height,
85 unsigned int depth)
86 {
87 width_ = width;
88 height_ = height;
89 depth_ = depth;
90 Invalidate();
91 }
92
93
94 void VolumeImageGeometry::SetAxialGeometry(const CoordinateSystem3D& geometry)
95 {
96 axialGeometry_ = geometry;
97 Invalidate();
98 }
99
100
101 void VolumeImageGeometry::SetVoxelDimensions(double x,
102 double y,
103 double z)
104 {
105 if (x <= 0 ||
106 y <= 0 ||
107 z <= 0)
108 {
109 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
110 }
111 else
112 {
113 LinearAlgebra::AssignVector(voxelDimensions_, x, y, z);
114 Invalidate();
115 }
116 }
117
118
119 const CoordinateSystem3D& VolumeImageGeometry::GetProjectionGeometry(VolumeProjection projection) const
120 {
121 switch (projection)
122 {
123 case VolumeProjection_Axial:
124 return axialGeometry_;
125
126 case VolumeProjection_Coronal:
127 return coronalGeometry_;
128
129 case VolumeProjection_Sagittal:
130 return sagittalGeometry_;
131
132 default:
133 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
134 }
135 }
136
137
138 Vector VolumeImageGeometry::GetVoxelDimensions(VolumeProjection projection) const
139 {
140 switch (projection)
141 {
142 case VolumeProjection_Axial:
143 return voxelDimensions_;
144
145 case VolumeProjection_Coronal:
146 return LinearAlgebra::CreateVector(voxelDimensions_[0], voxelDimensions_[2], voxelDimensions_[1]);
147
148 case VolumeProjection_Sagittal:
149 return LinearAlgebra::CreateVector(voxelDimensions_[1], voxelDimensions_[2], voxelDimensions_[0]);
150
151 default:
152 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
153 }
154 }
155
156
157 unsigned int VolumeImageGeometry::GetProjectionWidth(VolumeProjection projection) const
158 {
159 switch (projection)
160 {
161 case VolumeProjection_Axial:
162 return width_;
163
164 case VolumeProjection_Coronal:
165 return width_;
166
167 case VolumeProjection_Sagittal:
168 return height_;
169
170 default:
171 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
172 }
173 }
174
175
176 unsigned int VolumeImageGeometry::GetProjectionHeight(VolumeProjection projection) const
177 {
178 switch (projection)
179 {
180 case VolumeProjection_Axial:
181 return height_;
182
183 case VolumeProjection_Coronal:
184 return depth_;
185
186 case VolumeProjection_Sagittal:
187 return depth_;
188
189 default:
190 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
191 }
192 }
193
194
195 unsigned int VolumeImageGeometry::GetProjectionDepth(VolumeProjection projection) const
196 {
197 switch (projection)
198 {
199 case VolumeProjection_Axial:
200 return depth_;
201
202 case VolumeProjection_Coronal:
203 return height_;
204
205 case VolumeProjection_Sagittal:
206 return width_;
207
208 default:
209 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
210 }
211 }
212
213
214 Vector VolumeImageGeometry::GetCoordinates(float x,
215 float y,
216 float z) const
217 {
218 Vector p = LinearAlgebra::Product(transform_, LinearAlgebra::CreateVector(x, y, z, 1));
219
220 assert(LinearAlgebra::IsNear(p[3], 1)); // Affine transform, no perspective effect
221
222 // Back to non-homogeneous coordinates
223 return LinearAlgebra::CreateVector(p[0], p[1], p[2]);
224 }
225
226
227 bool VolumeImageGeometry::DetectProjection(VolumeProjection& projection,
228 const Vector& planeNormal) const
229 {
230 if (GeometryToolbox::IsParallel(planeNormal, axialGeometry_.GetNormal()))
231 {
232 projection = VolumeProjection_Axial;
233 return true;
234 }
235 else if (GeometryToolbox::IsParallel(planeNormal, coronalGeometry_.GetNormal()))
236 {
237 projection = VolumeProjection_Coronal;
238 return true;
239 }
240 else if (GeometryToolbox::IsParallel(planeNormal, sagittalGeometry_.GetNormal()))
241 {
242 projection = VolumeProjection_Sagittal;
243 return true;
244 }
245 else
246 {
247 return false;
248 }
249 }
250
251
252 bool VolumeImageGeometry::DetectSlice(VolumeProjection& projection,
253 unsigned int& slice,
254 const CoordinateSystem3D& plane) const
255 {
256 if (!DetectProjection(projection, plane.GetNormal()))
257 {
258 return false;
259 }
260
261 // Transforms the coordinates of the origin of the plane, into the
262 // coordinates of the axial geometry
263 const Vector& origin = plane.GetOrigin();
264 Vector p = LinearAlgebra::Product(
265 transformInverse_,
266 LinearAlgebra::CreateVector(origin[0], origin[1], origin[2], 1));
267
268 assert(LinearAlgebra::IsNear(p[3], 1));
269
270 double z;
271
272 switch (projection)
273 {
274 case VolumeProjection_Axial:
275 z = p[2];
276 break;
277
278 case VolumeProjection_Coronal:
279 z = p[1];
280 break;
281
282 case VolumeProjection_Sagittal:
283 z = p[0];
284 break;
285
286 default:
287 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
288 }
289
290 const unsigned int projectionDepth = GetProjectionDepth(projection);
291
292 z *= static_cast<double>(projectionDepth);
293 if (z < 0)
294 {
295 return false;
296 }
297
298 unsigned int d = static_cast<unsigned int>(std::floor(z));
299 if (d >= projectionDepth)
300 {
301 return false;
302 }
303 else
304 {
305 slice = d;
306 return true;
307 }
308 }
309 }