CustusX  15.8
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cxSliceComputer.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) 2008-2014, SINTEF Department of Medical Technology
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 1. Redistributions of source code must retain the above copyright notice,
11  this list of conditions and the following disclaimer.
12 
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 3. Neither the name of the copyright holder nor the names of its contributors
18  may be used to endorse or promote products derived from this software
19  without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 =========================================================================*/
32 
33 #include "cxSliceComputer.h"
34 #include "cxDefinitions.h"
35 #include <math.h>
36 
37 namespace cx
38 {
39 
40 SlicePlane::SlicePlane(const Vector3D& c_, const Vector3D& i_, const Vector3D& j_) :
41  c(c_), i(i_), j(j_)
42 {
43 }
44 
45 std::ostream& operator<<(std::ostream& s, const SlicePlane& val)
46 {
47  s << "center : " << val.c << std::endl;
48  s << "i_vector : " << val.i << std::endl;
49  s << "j_vector : " << val.j << std::endl;
50  return s;
51 }
52 
53 bool similar(const SlicePlane& a, const SlicePlane& b)
54 {
55  return similar(a.c, b.c) && similar(a.i, b.i) && similar(a.j, b.j);
56 }
57 
61  mClinicalApplication(mdNEUROLOGICAL),
62  mOrientType(otORTHOGONAL),
63  mPlaneType(ptAXIAL),
64  mFollowType(ftFIXED_CENTER),
65  mFixedCenter(Vector3D(0,0,0)),
66  m_rMt(Transform3D::Identity()),
67  mToolOffset(0.0),
68  mUseGravity(false),
69  mGravityDirection(Vector3D(0,0,-1)) ,
70  mUseViewOffset(false),
71  mViewportHeight(1),
72  mViewOffset(0.5),
73  mUseConstrainedViewOffset(false)
74 {
75 }
76 
78 {
79 }
80 
83 void SliceComputer::initializeFromPlane(PLANE_TYPE plane, bool useGravity, const Vector3D& gravityDir, bool useViewOffset, double viewportHeight, double toolViewOffset, CLINICAL_VIEW application, bool useConstrainedViewOffset)
84 {
85  setPlaneType(plane);
86  mClinicalApplication = application;
87 
88  if (plane == ptSAGITTAL || plane == ptCORONAL || plane == ptAXIAL )
89  {
92  }
93  else if (plane == ptANYPLANE || plane==ptRADIALPLANE || plane==ptSIDEPLANE)
94  {
97 
98  setGravity(useGravity, gravityDir);
99  setToolViewOffset(useViewOffset, viewportHeight, toolViewOffset, useConstrainedViewOffset); // TODO finish this one
100  }
101 }
102 
109 void SliceComputer::switchOrientationMode(ORIENTATION_TYPE type)
110 {
111  if (type==mOrientType)
112  return; // no change
113 
114  PLANE_TYPE newType = mPlaneType;
115 
116  if (type==otOBLIQUE) // ACS->ADR
117  {
118  switch (mPlaneType)
119  {
120  case ptSAGITTAL : newType = ptSIDEPLANE; break;
121  case ptCORONAL : newType = ptANYPLANE; break;
122  case ptAXIAL : newType = ptRADIALPLANE; break;
123  default: break;
124  }
125  }
126  else if (type==otORTHOGONAL)
127  {
128  switch (mPlaneType)
129  {
130  case ptSIDEPLANE : newType = ptSAGITTAL; break;
131  case ptANYPLANE : newType = ptCORONAL; break;
132  case ptRADIALPLANE : newType = ptAXIAL; break;
133  default: break;
134  }
135  }
136 
137  initializeFromPlane(newType, mUseGravity, mGravityDirection, mUseViewOffset, mViewportHeight, mViewOffset, mClinicalApplication);
138 }
139 
140 void SliceComputer::setClinicalApplication(CLINICAL_VIEW application)
141 {
142  mClinicalApplication = application;
143 }
144 
145 ORIENTATION_TYPE SliceComputer::getOrientationType() const
146 {
147  return mOrientType;
148 }
149 
150 PLANE_TYPE SliceComputer::getPlaneType() const
151 {
152  return mPlaneType;
153 }
154 
156 {
157  return m_rMt;
158 }
159 
164 {
165  m_rMt = rMt;
166 }
167 
171 void SliceComputer::setOrientationType(ORIENTATION_TYPE val)
172 {
173  mOrientType = val;
174 }
175 
178 void SliceComputer::setPlaneType(PLANE_TYPE val)
179 {
180  mPlaneType = val;
181 }
182 
187 {
188  mFixedCenter = center;
189 }
190 
195 void SliceComputer::setFollowType(FOLLOW_TYPE val)
196 {
197  mFollowType = val;
198 }
199 
203 void SliceComputer::setGravity(bool use, const Vector3D& dir)
204 {
205  mUseGravity = use;
206  mGravityDirection = dir;
207 }
208 
212 {
213  mToolOffset = val;
214 }
215 
220 void SliceComputer::setToolViewOffset(bool use, double viewportHeight, double viewOffset, bool useConstrainedViewOffset)
221 {
222  mUseViewOffset = use;
223  mViewportHeight = viewportHeight;
224  mViewOffset = viewOffset;
225  mUseConstrainedViewOffset = useConstrainedViewOffset;
226 }
227 
230 void SliceComputer::setToolViewportHeight(double viewportHeight)
231 {
232  mViewportHeight = viewportHeight;
233 }
234 
238 {
239  std::pair<Vector3D,Vector3D> basis = generateBasisVectors();
240  SlicePlane plane;
241  plane.i = basis.first;
242  plane.j = basis.second;
243  plane.c = Vector3D(0,0,mToolOffset);
244 
245  // transform position from tool to reference space
246  plane.c = m_rMt.coord(plane.c);
247  // transform orientation from tool to reference space for the oblique case only
248  if (mOrientType==otOBLIQUE)
249  {
250  plane.i = m_rMt.vector(plane.i);
251  plane.j = m_rMt.vector(plane.j);
252  }
253 
254  // orient planes so that gravity is down
255  plane = orientToGravity(plane);
256 
257  // try to to this also for oblique views, IF the ftFIXED_CENTER is set.
258  // use special acs centermod algo
259  plane.c = generateFixedIJCenter(mFixedCenter, plane.c, plane.i, plane.j);
260 
261  // set center so that it is a fixed distance from viewport top
262  plane = applyViewOffset(plane);
263 
264  return plane;
265 }
266 
278 SlicePlane SliceComputer::applyViewOffset(const SlicePlane& base) const
279 {
280  if (!mUseViewOffset)
281  {
282  return base;
283  }
284 
285  double centerOffset = this->getViewOffsetAbsoluteFromCenter();
286 
287  SlicePlane retval = base;
288  if (mUseConstrainedViewOffset)
289  {
290  Vector3D toolOffsetCenter = m_rMt.coord(Vector3D(0,0,mToolOffset));
291  Vector3D newCenter = toolOffsetCenter + centerOffset * base.j;
292  double toolOffsetDistance = dot(newCenter - base.c, base.j);
293 
294  Vector3D toolCenter = m_rMt.coord(Vector3D(0,0,0));
295  newCenter = toolCenter - centerOffset * base.j;
296  double toolDistance = dot(newCenter - base.c, base.j);
297  double usedDistance = std::min(toolOffsetDistance, toolDistance);
298  retval.c = base.c + usedDistance * base.j; // extract j-component of newCenter
299  }
300  else
301  {
302  Vector3D toolCenter = m_rMt.coord(Vector3D(0,0,mToolOffset));
303  Vector3D newCenter = toolCenter - centerOffset * base.j;
304  double distance = dot(newCenter - base.c, base.j);
305  retval.c = base.c + distance * base.j; // extract j-component of newCenter
306  }
307  return retval;
308 }
309 
310 double SliceComputer::getViewOffsetAbsoluteFromCenter() const
311 {
312  if (mPlaneType==ptRADIALPLANE)
313  return 0; // position in the center
314 
315  return mViewportHeight*(0.5-mViewOffset);
316 }
317 
324 std::pair<Vector3D,Vector3D> SliceComputer::generateBasisVectors() const
325 {
326  switch (mClinicalApplication)
327  {
328  case mdRADIOLOGICAL:
329  return this->generateBasisVectorsRadiology();
330  case mdNEUROLOGICAL:
331  default:
332  return this->generateBasisVectorsNeurology();
333  }
334 }
335 
339 std::pair<Vector3D,Vector3D> SliceComputer::generateBasisVectorsNeurology() const
340 {
341  switch (mPlaneType)
342  {
343  // use left-right ordering for axial/coronal
344  case ptAXIAL: return std::make_pair(Vector3D(-1, 0, 0), Vector3D( 0,-1, 0));
345  case ptCORONAL: return std::make_pair(Vector3D(-1, 0, 0), Vector3D( 0, 0, 1));
346  case ptSAGITTAL: return std::make_pair(Vector3D( 0, 1, 0), Vector3D( 0, 0, 1));
347 
348  // use planes corresponding to the cx Tool definitions
349  case ptANYPLANE: return std::make_pair(Vector3D( 0,-1, 0), Vector3D( 0, 0,-1));
350  case ptSIDEPLANE: return std::make_pair(Vector3D(-1, 0, 0), Vector3D( 0, 0,-1));
351  case ptRADIALPLANE: return std::make_pair(Vector3D( 0,-1, 0), Vector3D(-1, 0, 0));
352  default:
353  throw std::exception();
354  }
355 }
356 
360 std::pair<Vector3D,Vector3D> SliceComputer::generateBasisVectorsRadiology() const
361 {
362  switch (mPlaneType)
363  {
364  // use right-left ordering for axial/coronal
365  case ptAXIAL: return std::make_pair(Vector3D( 1, 0, 0), Vector3D( 0,-1, 0));
366  case ptCORONAL: return std::make_pair(Vector3D( 1, 0, 0), Vector3D( 0, 0, 1));
367  case ptSAGITTAL: return std::make_pair(Vector3D( 0, 1, 0), Vector3D( 0, 0, 1));
368 
369  // use planes corresponding to the cx Tool definitions
370  case ptANYPLANE: return std::make_pair(Vector3D( 0,-1, 0), Vector3D( 0, 0,-1));
371  case ptSIDEPLANE: return std::make_pair(Vector3D(-1, 0, 0), Vector3D( 0, 0,-1));
372  case ptRADIALPLANE: return std::make_pair(Vector3D( 0,-1, 0), Vector3D(-1, 0, 0));
373  default:
374  throw std::exception();
375  }
376 }
377 
378 
386 Vector3D SliceComputer::generateFixedIJCenter(const Vector3D& center_r, const Vector3D& cross_r, const Vector3D& i, const Vector3D& j) const
387 {
388  if (mFollowType==ftFIXED_CENTER)
389  {
390  // r is REF, s is SLICE
391  Transform3D M_rs = createTransformIJC(i, j, Vector3D(0,0,0)); // transform from data to slice, zero center.
392  Transform3D M_sr = M_rs.inv();
393  Vector3D center_s = M_sr.coord(center_r);
394  Vector3D cross_s = M_sr.coord(cross_r);
395  // in SLICE space, use {xy} values from center and {z} value from cross.
396  Vector3D q_s(center_s[0], center_s[1], cross_s[2]);
397  Vector3D q_r = M_rs.coord(q_s);
398  return q_r;
399  }
400  return cross_r;
401 }
402 
414 SlicePlane SliceComputer::orientToGravity(const SlicePlane& base) const
415 {
416  if (!mUseGravity)
417  {
418  return base;
419  }
420 
421  SlicePlane retval = base;
422  const Vector3D k = cross(base.i, base.j); // plane normal. Constant
423  Vector3D up;
424  up = -mGravityDirection; // normal case
425 
426  // weight of nongravity, 0=<w=<1, 1 means dont use gravity
427  double w_n = dot(up, k);
428  w_n = w_n*w_n; // square to keep stability near normal use.
429 
430  Vector3D i_g = cross(up, k); // |i_g| varies from 0 to 1 depending on 1-w_n
431  Vector3D i_n = base.i; // |i_n|==1
432 
433 
434  // set i vector to a weighted mean of the two definitions
435  // can also experiment with a tanh function or simply a linear interpolation
436  //
437  // Note: i_g is already small here if w_n is small, this will increase
438  // the effect of i_n. Investigate.
439  //
440  retval.i = i_g*(1.0-w_n) + i_n*w_n;
441  retval.i = retval.i.normal(); // |i|==1
442  retval.j = cross(k, retval.i);
443 
444  return retval;
445 }
446 
447 
448 } // namespace cx
Vector3D j
defines the second axis of the plane. unit vector
void setToolViewportHeight(double viewportHeight)
ptCORONAL
a slice seen from the front of the patient
Definition: cxDefinitions.h:56
A 2D slice plane in 3D. i,j are perpendicular unit vectors.
ftFOLLOW_TOOL
center follows tool
Definition: cxDefinitions.h:67
otOBLIQUE
orient planes relative to the tool space
Definition: cxDefinitions.h:50
mdRADIOLOGICAL
Definition: cxDefinitions.h:75
ftFIXED_CENTER
center is set.
Definition: cxDefinitions.h:67
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
void setToolViewOffset(bool use, double viewportHeight, double viewOffset, bool useConstrainedViewOffset=false)
void setClinicalApplication(CLINICAL_VIEW application)
ptAXIAL
a slice seen from the top of the patient
Definition: cxDefinitions.h:56
PLANE_TYPE getPlaneType() const
void setOrientationType(ORIENTATION_TYPE val)
bool similar(const DoubleBoundingBox3D &a, const DoubleBoundingBox3D &b, double tol)
Vector3D cross(const Vector3D &a, const Vector3D &b)
compute cross product of a and b.
Definition: cxVector3D.cpp:62
void setToolOffset(double val)
ptSAGITTAL
a slice seen from the side of the patient
Definition: cxDefinitions.h:56
Transform3D createTransformIJC(const Vector3D &ivec, const Vector3D &jvec, const Vector3D &center)
Vector3D c
defines the center of the plane
void initializeFromPlane(PLANE_TYPE plane, bool useGravity, const Vector3D &gravityDir, bool useViewOffset, double viewportHeight, double toolViewOffset, CLINICAL_VIEW application, bool useConstrainedViewOffset=false)
void setPlaneType(PLANE_TYPE val)
otORTHOGONAL
orient planes relative to the image/reference space.
Definition: cxDefinitions.h:50
void setFixedCenter(const Vector3D &center)
void setToolPosition(const Transform3D &rMt)
void switchOrientationMode(ORIENTATION_TYPE type)
double dot(const Vector3D &a, const Vector3D &b)
compute inner product (or dot product) of a and b.
Definition: cxVector3D.cpp:67
std::ostream & operator<<(std::ostream &s, const IntBoundingBox3D &data)
Eigen::Vector3d Vector3D
Vector3D is a representation of a point or vector in 3D.
Definition: cxVector3D.h:63
ptRADIALPLANE
y-rotated 90* relative to anyplane (bird's view)
Definition: cxDefinitions.h:56
Vector3D i
defines the first axis of the plane. unit vector
Transform3D getToolPosition() const
mdNEUROLOGICAL
Definition: cxDefinitions.h:75
ptANYPLANE
a plane aligned with the tool base plane
Definition: cxDefinitions.h:56
void setFollowType(FOLLOW_TYPE val)
void setGravity(bool use, const Vector3D &dir)
ORIENTATION_TYPE getOrientationType() const
SlicePlane getPlane() const
ptSIDEPLANE
z-rotated 90* relative to anyplane (dual anyplane)
Definition: cxDefinitions.h:56