Fraxinus  17.12
An IGT application
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 {
74 }
75 
77 {
78 }
79 
82 void SliceComputer::initializeFromPlane(PLANE_TYPE plane, bool useGravity, const Vector3D& gravityDir, bool useViewOffset, double viewportHeight, double toolViewOffset, CLINICAL_VIEW application)
83 {
84  setPlaneType(plane);
85  mClinicalApplication = application;
86 
87  if (plane == ptSAGITTAL || plane == ptCORONAL || plane == ptAXIAL )
88  {
91  }
92  else if (plane == ptANYPLANE || plane==ptRADIALPLANE || plane==ptSIDEPLANE)
93  {
96 
97  setGravity(useGravity, gravityDir);
98  setToolViewOffset(useViewOffset, viewportHeight, toolViewOffset); // TODO finish this one
99  }
100  else if (plane==ptTOOLSIDEPLANE)
101  {
104  setGravity(useGravity, gravityDir);
105  }
106 }
107 
108 void SliceComputer::setClinicalApplication(CLINICAL_VIEW application)
109 {
110  mClinicalApplication = application;
111 }
112 
113 ORIENTATION_TYPE SliceComputer::getOrientationType() const
114 {
115  return mOrientType;
116 }
117 
118 PLANE_TYPE SliceComputer::getPlaneType() const
119 {
120  return mPlaneType;
121 }
122 
123 FOLLOW_TYPE SliceComputer::getFollowType() const
124 {
125  return mFollowType;
126 }
127 
129 {
130  return m_rMt;
131 }
132 
137 {
138  m_rMt = rMt;
139 }
140 
144 void SliceComputer::setOrientationType(ORIENTATION_TYPE val)
145 {
146  mOrientType = val;
147 }
148 
151 void SliceComputer::setPlaneType(PLANE_TYPE val)
152 {
153  mPlaneType = val;
154 }
155 
160 {
161  mFixedCenter = center;
162 }
163 
168 void SliceComputer::setFollowType(FOLLOW_TYPE val)
169 {
170  mFollowType = val;
171 }
172 
176 void SliceComputer::setGravity(bool use, const Vector3D& dir)
177 {
178  mUseGravity = use;
179  mGravityDirection = dir;
180 }
181 
185 {
186  mToolOffset = val;
187 }
188 
193 void SliceComputer::setToolViewOffset(bool use, double viewportHeight, double viewOffset)
194 {
195  mUseViewOffset = use;
196  mViewportHeight = viewportHeight;
197  mViewOffset = viewOffset;
198 }
199 
202 void SliceComputer::setToolViewportHeight(double viewportHeight)
203 {
204  mViewportHeight = viewportHeight;
205 }
206 
210 {
211  std::pair<Vector3D,Vector3D> basis = generateBasisVectors();
212  SlicePlane plane;
213  plane.i = basis.first;
214  plane.j = basis.second;
215  plane.c = Vector3D(0,0,mToolOffset);
216 
217  // transform position from tool to reference space
218  plane.c = m_rMt.coord(plane.c);
219  // transform orientation from tool to reference space for the oblique case only
220  if (mOrientType==otOBLIQUE)
221  {
222  plane.i = m_rMt.vector(plane.i);
223  plane.j = m_rMt.vector(plane.j);
224  }
225 
226  if (mPlaneType == ptTOOLSIDEPLANE)
227  {
228  plane = this->orientToGravityAroundToolZAxisAndAlongTheOperatingTable(plane);
229  }
230  else
231  {
232  plane = orientToGravity(plane);
233  }
234 
235  // try to to this also for oblique views, IF the ftFIXED_CENTER is set.
236  // use special acs centermod algo
237  plane.c = generateFixedIJCenter(mFixedCenter, plane.c, plane.i, plane.j);
238 
239  // set center so that it is a fixed distance from viewport top
240  plane = applyViewOffset(plane);
241 
242  return plane;
243 }
244 
254 SlicePlane SliceComputer::applyViewOffset(const SlicePlane& base) const
255 {
256  if (!mUseViewOffset)
257  {
258  return base;
259  }
260 
261  double centerOffset = this->getViewOffsetAbsoluteFromCenter();
262 
263  SlicePlane retval = base;
264 
265  // limit by tooloffset
266  Vector3D toolOffsetCenter = m_rMt.coord(Vector3D(0,0,mToolOffset));
267  Vector3D newCenter = toolOffsetCenter + centerOffset * base.j;
268  double toolOffsetDistance = dot(newCenter - base.c, base.j);
269 
270  // limit by tooltip
271  Vector3D toolCenter = m_rMt.coord(Vector3D(0,0,0));
272  newCenter = toolCenter - centerOffset * base.j;
273  double toolDistance = dot(newCenter - base.c, base.j);
274 
275  // select a dist and apply
276  double usedDistance = std::min(toolOffsetDistance, toolDistance);
277  retval.c = base.c + usedDistance * base.j; // extract j-component of newCenter
278 
279  return retval;
280 }
281 
282 double SliceComputer::getViewOffsetAbsoluteFromCenter() const
283 {
284  if (mPlaneType==ptRADIALPLANE)
285  return 0; // position in the center
286 
287  return mViewportHeight*(0.5-mViewOffset);
288 }
289 
296 std::pair<Vector3D,Vector3D> SliceComputer::generateBasisVectors() const
297 {
298  switch (mClinicalApplication)
299  {
300  case mdRADIOLOGICAL:
301  return this->generateBasisVectorsRadiology();
302  case mdNEUROLOGICAL:
303  default:
304  return this->generateBasisVectorsNeurology();
305  }
306 }
307 
311 std::pair<Vector3D,Vector3D> SliceComputer::generateBasisVectorsNeurology() const
312 {
313  switch (mPlaneType)
314  {
315  // use left-right ordering for axial/coronal
316  case ptAXIAL: return std::make_pair(Vector3D(-1, 0, 0), Vector3D( 0,-1, 0));
317  case ptCORONAL: return std::make_pair(Vector3D(-1, 0, 0), Vector3D( 0, 0, 1));
318  case ptSAGITTAL: return std::make_pair(Vector3D( 0, 1, 0), Vector3D( 0, 0, 1));
319 
320  // use planes corresponding to the cx Tool definitions
321  case ptANYPLANE: return std::make_pair(Vector3D( 0,-1, 0), Vector3D( 0, 0,-1));
322  case ptSIDEPLANE: return std::make_pair(Vector3D(-1, 0, 0), Vector3D( 0, 0,-1));
323  case ptRADIALPLANE: return std::make_pair(Vector3D( 0,-1, 0), Vector3D(-1, 0, 0));
324  case ptTOOLSIDEPLANE: return std::make_pair(Vector3D(-1, 0, 0), Vector3D( 0, 0,-1)); //SIDE
325  default:
326  throw std::exception();
327  }
328 }
329 
333 std::pair<Vector3D,Vector3D> SliceComputer::generateBasisVectorsRadiology() const
334 {
335  switch (mPlaneType)
336  {
337  // use right-left ordering for axial/coronal
338  case ptAXIAL: return std::make_pair(Vector3D( 1, 0, 0), Vector3D( 0,-1, 0));
339  case ptCORONAL: return std::make_pair(Vector3D( 1, 0, 0), Vector3D( 0, 0, 1));
340  case ptSAGITTAL: return std::make_pair(Vector3D( 0, 1, 0), Vector3D( 0, 0, 1));
341 
342  // use planes corresponding to the cx Tool definitions
343  case ptANYPLANE: return std::make_pair(Vector3D( 0,-1, 0), Vector3D( 0, 0,-1));
344  case ptSIDEPLANE: return std::make_pair(Vector3D(-1, 0, 0), Vector3D( 0, 0,-1));
345  case ptRADIALPLANE: return std::make_pair(Vector3D( 0,-1, 0), Vector3D(-1, 0, 0));
346  case ptTOOLSIDEPLANE: return std::make_pair(Vector3D(-1, 0, 0), Vector3D( 0, 0,-1)); //SIDE
347  default:
348  throw std::exception();
349  }
350 }
351 
359 Vector3D SliceComputer::generateFixedIJCenter(const Vector3D& center_r, const Vector3D& cross_r, const Vector3D& i, const Vector3D& j) const
360 {
361  if (mFollowType==ftFIXED_CENTER)
362  {
363  // r is REF, s is SLICE
364  Transform3D M_rs = createTransformIJC(i, j, Vector3D(0,0,0)); // transform from data to slice, zero center.
365  Transform3D M_sr = M_rs.inv();
366  Vector3D center_s = M_sr.coord(center_r);
367  Vector3D cross_s = M_sr.coord(cross_r);
368  // in SLICE space, use {xy} values from center and {z} value from cross.
369  Vector3D q_s(center_s[0], center_s[1], cross_s[2]);
370  Vector3D q_r = M_rs.coord(q_s);
371  return q_r;
372  }
373  return cross_r;
374 }
375 
387 SlicePlane SliceComputer::orientToGravity(const SlicePlane& base) const
388 {
389  if (!mUseGravity)
390  {
391  return base;
392  }
393 
394  SlicePlane retval = base;
395  const Vector3D k = cross(base.i, base.j); // plane normal. Constant
396  Vector3D up;
397  up = -mGravityDirection; // normal case
398 
399  // weight of nongravity, 0=<w=<1, 1 means dont use gravity
400  double w_n = dot(up, k);
401  w_n = w_n*w_n; // square to keep stability near normal use.
402 
403  Vector3D i_g = cross(up, k); // |i_g| varies from 0 to 1 depending on 1-w_n
404  Vector3D i_n = base.i; // |i_n|==1 //It seems to me that i_n might need a change to e.g. i_n = -base.j, to be good in the singularity situation. Look into that if using this method later. jone, 20160712
405 
406  // set i vector to a weighted mean of the two definitions
407  // can also experiment with a tanh function or simply a linear interpolation
408  //
409  // Note: i_g is already small here if w_n is small, this will increase
410  // the effect of i_n. Investigate.
411  //
412  retval.i = i_g*(1.0-w_n) + i_n*w_n;
413  retval.i = retval.i.normal(); // |i|==1
414  retval.j = cross(k, retval.i);
415 
416  return retval;
417 }
418 
442 SlicePlane SliceComputer::orientToGravityAroundToolZAxisAndAlongTheOperatingTable(const SlicePlane &base) const
443 {
444  if (!mUseGravity)
445  {
446  return base;
447  }
448 
449  SlicePlane retval = base;
450  Vector3D up = -mGravityDirection;
451 
452  Vector3D k_neg = -cross(base.i, base.j);
453  Vector3D toolVector = m_rMt.vector(Vector3D(0, 0, 1));
454  Vector3D i_perpendicular = cross(up, toolVector).normal();
455 
456  double w_n = this->getWeightForAngularDifference(up, toolVector);
457 
458  i_perpendicular = i_perpendicular*(1.0-w_n) + k_neg*w_n;
459 
460  Vector3D i_mark = cross(i_perpendicular, up).normal();
461  Vector3D j_mark = up;
462 
463  retval.i = i_mark;
464  retval.j = j_mark;
465 
466  return retval;
467 }
468 
474 double SliceComputer::getWeightForAngularDifference(Vector3D a, Vector3D b) const
475 {
476  double w_n = dot(a, b);
477  w_n = fabs(w_n);
478  // w_n = 0 : normal case
479  // w_n = 1 : singularity
480 
481  double cutoff = sqrt(3.0)/2.0; // cutoff at 30*, i.e. use only toolvector up to that angle between up and tool
482  if (w_n<cutoff)
483  w_n = 0;
484  else
485  w_n = (w_n-cutoff)/(1.0-cutoff);
486  return w_n;
487 }
488 
489 
490 } // 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
void setToolViewOffset(bool use, double viewportHeight, double viewOffset)
A 2D slice plane in 3D. i,j are perpendicular unit vectors.
ftFOLLOW_TOOL
center follows tool
Definition: cxDefinitions.h:68
otOBLIQUE
orient planes relative to the tool space
Definition: cxDefinitions.h:50
mdRADIOLOGICAL
Definition: cxDefinitions.h:76
ftFIXED_CENTER
center is set.
Definition: cxDefinitions.h:68
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
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)
Vector3D cross(const Vector3D &a, const Vector3D &b)
compute cross product of a and b.
Definition: cxVector3D.cpp:62
void setToolOffset(double val)
FOLLOW_TYPE getFollowType() const
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 setPlaneType(PLANE_TYPE val)
otORTHOGONAL
orient planes relative to the image/reference space.
Definition: cxDefinitions.h:50
void setFixedCenter(const Vector3D &center)
ptTOOLSIDEPLANE
z-rotated 90* relative to anyplane like side plane, but always kept oriented like the plane defined b...
Definition: cxDefinitions.h:56
void setToolPosition(const Transform3D &rMt)
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)
void initializeFromPlane(PLANE_TYPE plane, bool useGravity, const Vector3D &gravityDir, bool useViewOffset, double viewportHeight, double toolViewOffset, CLINICAL_VIEW application)
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&#39;s view)
Definition: cxDefinitions.h:56
Vector3D i
defines the first axis of the plane. unit vector
bool similar(const CameraInfo &lhs, const CameraInfo &rhs, double tol)
Transform3D getToolPosition() const
mdNEUROLOGICAL
Definition: cxDefinitions.h:76
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
Namespace for all CustusX production code.