CustusX  16.12
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cxCustomMetric.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 "cxCustomMetric.h"
34 
35 #include <vtkImageData.h>
36 #include "cxBoundingBox3D.h"
37 #include "cxTypeConversions.h"
38 #include "cxPatientModelService.h"
39 #include "cxTypeConversions.h"
40 #include "cxSpaceProvider.h"
41 #include "cxSpaceListener.h"
42 #include "cxData.h"
43 #include "cxMesh.h"
44 #include "cxImage.h"
45 #include "cxLogger.h"
46 
47 namespace cx
48 {
49 
50 CustomMetric::CustomMetric(const QString& uid, const QString& name, PatientModelServicePtr dataManager, SpaceProviderPtr spaceProvider) :
51  DataMetric(uid, name, dataManager, spaceProvider), mShowDistanceMarkers(false), mDistanceMarkerVisibility(50)
52 {
53  mArguments.reset(new MetricReferenceArgumentList(QStringList() << "position" << "direction"));
54  mArguments->setValidArgumentTypes(QStringList() << "pointMetric" << "frameMetric");
55  connect(mArguments.get(), SIGNAL(argumentsChanged()), this, SIGNAL(transformChanged()));
56  connect(this, &CustomMetric::propertiesChanged, this, &CustomMetric::onPropertiesChanged);
57  mDefineVectorUpMethod = mDefineVectorUpMethods.table;
58  mModelUid = "";
59  mScaleToP1 = false;
60  mOffsetFromP0 = 0.0;
61  mOffsetFromP1 = 0.0;
62  mRepeatDistance = 0.0;
63  mTranslationOnly = false;
64  mTextureFollowTool = false;
65 }
66 
67 bool CustomMetric::needForToolListenerHasChanged() const
68 {
69  bool toolDefinesUp = mDefineVectorUpMethod == mDefineVectorUpMethods.tool;
70  bool toolListenerDefined = mToolListener.get()!=NULL;
71 
72  if (mTextureFollowTool != toolListenerDefined || toolDefinesUp != toolListenerDefined)
73  return true;
74  else
75  return false;
76 }
77 
78 
79 void CustomMetric::createOrDestroyToolListener()
80 {
81  if (this->needForToolListenerHasChanged())
82  {
83  bool toolDefinesUp = mDefineVectorUpMethod == mDefineVectorUpMethods.tool;
84  if (mTextureFollowTool || toolDefinesUp)
85  {
86  mToolListener = mSpaceProvider->createListener();
87  mToolListener->setSpace(CoordinateSystem(csTOOL_OFFSET, "active"));
88  connect(mToolListener.get(), &SpaceListener::changed, this, &CustomMetric::transformChanged);
89  }
90  else
91  {
92  disconnect(mToolListener.get(), &SpaceListener::changed, this, &CustomMetric::transformChanged);
93  mToolListener.reset();
94  }
95  }
96 }
97 
98 void CustomMetric::onPropertiesChanged()
99 {
100  this->createOrDestroyToolListener();
101 }
102 
103 CustomMetric::DefineVectorUpMethods CustomMetric::getDefineVectorUpMethods() const
104 {
105  return mDefineVectorUpMethods;
106 }
107 
108 
109 CustomMetricPtr CustomMetric::create(QString uid, QString name, PatientModelServicePtr dataManager, SpaceProviderPtr spaceProvider)
110 {
111  return CustomMetricPtr(new CustomMetric(uid, name, dataManager, spaceProvider));
112 }
113 
115 {
116 }
117 
118 void CustomMetric::addXml(QDomNode& dataNode)
119 {
120  DataMetric::addXml(dataNode);
121 
122  mArguments->addXml(dataNode);
123 
124  QDomElement elem = dataNode.toElement();
125  elem.setAttribute("definevectorup", mDefineVectorUpMethod);
126  elem.setAttribute("meshUid", mModelUid);
127 
128  elem.setAttribute("scaleToP1", mScaleToP1);
129  elem.setAttribute("offsetFromP0", mOffsetFromP0);
130  elem.setAttribute("offsetFromP1", mOffsetFromP1);
131  elem.setAttribute("repeatDistance", mRepeatDistance);
132  elem.setAttribute("showDistance", mShowDistanceMarkers);
133  elem.setAttribute("distanceMarkerVisibility", mDistanceMarkerVisibility);
134  elem.setAttribute("translationOnly", mTranslationOnly);
135  elem.setAttribute("textureFollowTool", mTextureFollowTool);
136 }
137 
138 void CustomMetric::parseXml(QDomNode& dataNode)
139 {
140  DataMetric::parseXml(dataNode);
141 
142  mArguments->parseXml(dataNode, mDataManager->getDatas());
143 
144  QDomElement elem = dataNode.toElement();
145  mDefineVectorUpMethod = elem.attribute("definevectorup", qstring_cast(mDefineVectorUpMethod));
146  mModelUid = elem.attribute("meshUid", qstring_cast(mModelUid));
147  mScaleToP1 = elem.attribute("scaleToP1", QString::number(mScaleToP1)).toInt();
148  mOffsetFromP0 = elem.attribute("offsetFromP0", QString::number(mOffsetFromP0)).toDouble();
149  mOffsetFromP1 = elem.attribute("offsetFromP1", QString::number(mOffsetFromP1)).toDouble();
150  mRepeatDistance = elem.attribute("repeatDistance", QString::number(mRepeatDistance)).toDouble();
151  mShowDistanceMarkers = elem.attribute("showDistance", QString::number(mShowDistanceMarkers)).toInt();
152  mDistanceMarkerVisibility = elem.attribute("distanceMarkerVisibility", QString::number(mDistanceMarkerVisibility)).toDouble();
153  mTranslationOnly = elem.attribute("translationOnly", QString::number(mTranslationOnly)).toInt();
154  mTextureFollowTool = elem.attribute("textureFollowTool", QString::number(mTextureFollowTool)).toInt();
155 
156  this->onPropertiesChanged();
157 }
158 
160 {
161  return !mArguments->getRefCoords().empty();
162 }
163 
165 {
166  return mArguments->getRefCoords().front();
167 }
168 
170 {
171  return DoubleBoundingBox3D::fromCloud(mArguments->getRefCoords());
172 }
173 
174 std::vector<Vector3D> CustomMetric::getPointCloud() const
175 {
176  std::vector<Vector3D> retval;
177 
178  DataPtr model = this->getModel();
179 
180  std::vector<Transform3D> pos = this->calculateOrientations();
181  std::vector<Vector3D> cloud;
182  Transform3D rrMd;
183 
184  if (model)
185  {
186  rrMd = model->get_rMd();
187  cloud = model->getPointCloud();
188  }
189  else
190  {
191  cloud.push_back(Vector3D::Zero());
192  rrMd = Transform3D::Identity();
193  }
194 
195  for (unsigned i=0; i<pos.size(); ++i)
196  {
197  Transform3D rMd = pos[i] * rrMd;
198 
199  for (unsigned j=0; j<cloud.size(); ++j)
200  {
201  Vector3D p_r = rMd.coord(cloud[j]);
202  retval.push_back(p_r);
203  }
204  }
205 
206  return retval;
207 }
208 
210 {
211  Vector3D zeroPos;
212  std::vector<Vector3D> coords = mArguments->getRefCoords();
213  if (coords.empty())
214  return zeroPos;
215  Vector3D p0 = coords[0];
216 
217  Vector3D dir = this->getDirection();
218  Vector3D vup = this->getVectorUp();
219  Vector3D scale = this->getScale();
220 
221  zeroPos = this->calculateOrientation(p0, dir, vup, scale).coord(Vector3D(0,0,0));
222 
223  return zeroPos;
224 }
225 
226 std::vector<Vector3D> CustomMetric::getPositions() const
227 {
228  std::vector<Vector3D> retval;
229  std::vector<Vector3D> coords = mArguments->getRefCoords();
230  if (coords.size() < 2)
231  return retval;
232 
233  Vector3D p0 = coords[0];
234  Vector3D p1 = coords[1];
235  Vector3D dir = getDirection();
236  double fullDist = dot(dir, p1-p0);
237 
238  int reps = this->getRepeatCount();
239  for (int i=0; i<reps; ++i)
240  {
241  double dist = mOffsetFromP0 + mRepeatDistance*i;
242  Vector3D p = p0 + dir*dist;
243  retval.push_back(p);
244  }
245 
246  return retval;
247 }
248 
250 {
251  std::vector<Vector3D> coords = mArguments->getRefCoords();
252  if (coords.size() < 2)
253  return 0;
254 
255  Vector3D p0 = coords[0];
256  Vector3D p1 = coords[1];
257  Vector3D dir = getDirection();
258 
259  int reps = 1;
260  if (!similar(mRepeatDistance, 0.0))
261  reps = (dot(p1-p0, dir)-mOffsetFromP0-mOffsetFromP1)/mRepeatDistance + 1;
262  reps = std::min(100, reps);
263  reps = std::max(reps, 1);
264 
265  return reps;
266 }
267 
268 
269 Vector3D CustomMetric::getDirection() const
270 {
271  std::vector<Vector3D> coords = mArguments->getRefCoords();
272  if (coords.size()<2)
273  return Vector3D::UnitZ();
274  Vector3D diff = (coords[1]-coords[0]);
275  if (similar(diff.length(), 0.0))
276  return Vector3D(0,1,0);
277  return diff.normal();
278 }
279 
280 Vector3D CustomMetric::getVectorUp() const
281 {
282  if(mDefineVectorUpMethod == mDefineVectorUpMethods.connectedFrameInP1)
283  {
284  std::vector<Transform3D> transforms = mArguments->getRefFrames();
285  if (transforms.size()<2)
286  return Vector3D::UnitZ();
287 
288  Transform3D rMframe = transforms[1];
289  Vector3D upVector = rMframe.vector(Vector3D(-1,0,0));
290 
291  return upVector;
292  }
293  else if (mDefineVectorUpMethod == mDefineVectorUpMethods.tool)
294  {
295  Transform3D rMt = mSpaceProvider->getActiveToolTipTransform(CoordinateSystem::reference(), true);
296  Vector3D toolUp = -Vector3D::UnitX();
297  return rMt.vector(toolUp);
298  }
299  else
300  {
301  return mDataManager->getOperatingTable().getVectorUp();
302  }
303 }
304 
305 
307 {
308  if (!model)
309  return;
310 
311  if (!this->getTextureFollowTool() || !model->hasTexture())
312  return;
313 
314  // special case:
315  // Project tool position down to the model, then set that position as
316  // the texture x pos.
317 
318  Transform3D rMt = mSpaceProvider->getActiveToolTipTransform(CoordinateSystem::reference());
319  Transform3D rMd = rMrr * model->get_rMd();
320  Vector3D t_r = rMt.coord(Vector3D::Zero());
321  Vector3D td_r = rMt.vector(Vector3D::UnitZ());
322 
323  DoubleBoundingBox3D bb_d = model->boundingBox();
324  Vector3D bl = bb_d.bottomLeft();
325  Vector3D tr = bb_d.topRight();
326  Vector3D c = (bl+tr)/2;
327  Vector3D x_min_r(c[0], bl[1], c[2]);
328  Vector3D x_max_r(c[0], tr[1], c[2]);
329  x_min_r = rMd.coord(x_min_r);
330  x_max_r = rMd.coord(x_max_r);
331 
332  double t_x = dot(t_r, td_r);
333  double bbmin_x = dot(x_min_r, td_r);
334  double bbmax_x = dot(x_max_r, td_r);
335  double range = bbmax_x-bbmin_x;
336  if (similar(range, 0.0))
337  range = 1.0E-6;
338  double s = (t_x-bbmin_x)/range;
339  model->getTextureData().getPositionY()->setValue(s);
340 }
341 
342 Vector3D CustomMetric::getScale() const
343 {
344  if (!mScaleToP1 || !this->getModel() || this->getModel()->getType() == "image")
345  return Vector3D::Ones();
346 
347  DoubleBoundingBox3D bounds = this->getModel()->boundingBox();
348  bounds = transform(this->getModel()->get_rMd(), bounds);
349 
350  std::vector<Vector3D> coords = mArguments->getRefCoords();
351  double height = (coords[1] - coords[0]).length();
352 
353  Vector3D dir = this->getDirection();
354  double p0 = dot(coords[0], dir);
355  double p1 = dot(coords[1], dir);
356 
357  height = p1 - p0;
358  height -= (mOffsetFromP0 + mOffsetFromP1);
359 
360  Vector3D scale(1,
361  height/bounds.range()[1],
362  1);
363  return scale;
364 }
365 
367 {
368  return QString("%1 %2")
369  .arg(this->getSingleLineHeader())
370  .arg(qstring_cast(""));
371 }
372 
374 {
375  return mDefineVectorUpMethod;
376 }
377 
378 void CustomMetric::setDefineVectorUpMethod(QString defineVectorUpMethod)
379 {
380  mDefineVectorUpMethod = defineVectorUpMethod;
381 }
382 
383 void CustomMetric::setModelUid(QString val)
384 {
385  mModelUid = val;
386  emit propertiesChanged();
387 }
388 
390 {
391  return mModelUid;
392 }
393 
395 {
396  return mDataManager->getData(mModelUid);
397 }
398 
400 {
401  if (mScaleToP1 == val)
402  return;
403  mScaleToP1 = val;
404  emit propertiesChanged();
405 }
406 
408 {
409  return mScaleToP1;
410 }
411 
413 {
414  if (mOffsetFromP0 == val)
415  return;
416  mOffsetFromP0 = val;
417  emit propertiesChanged();
418 }
419 
421 {
422  return mOffsetFromP0;
423 }
424 
426 {
427  if (mOffsetFromP1 == val)
428  return;
429  mOffsetFromP1 = val;
430  emit propertiesChanged();
431 }
432 
434 {
435  return mOffsetFromP1;
436 }
437 
439 {
440  if (mRepeatDistance == val)
441  return;
442  mRepeatDistance = val;
443  emit propertiesChanged();
444 }
445 
447 {
448  return mRepeatDistance;
449 }
450 
452 {
453  if(mShowDistanceMarkers == show)
454  return;
455  mShowDistanceMarkers = show;
456  emit propertiesChanged();
457 }
458 
460 {
461  return mShowDistanceMarkers;
462 }
464 {
465  if (mTranslationOnly == val)
466  return;
467  mTranslationOnly = val;
468  emit propertiesChanged();
469 }
470 
472 {
473  if (mDistanceMarkerVisibility == val)
474  return;
475  mDistanceMarkerVisibility = val;
476  emit propertiesChanged();
477 }
478 
480 {
481  return mDistanceMarkerVisibility;
482 }
483 
485 {
486  return mTranslationOnly;
487 }
488 
490 {
491  if (mTextureFollowTool == val)
492  return;
493  mTextureFollowTool = val;
494  emit propertiesChanged();
495 }
496 
498 {
499  return mTextureFollowTool;
500 }
501 
502 QStringList CustomMetric::DefineVectorUpMethods::getAvailableDefineVectorUpMethods() const
503 {
504  QStringList retval;
505  retval << table;
506  retval << connectedFrameInP1;
507  retval << tool;
508  return retval;
509 }
510 
511 std::map<QString, QString> CustomMetric::DefineVectorUpMethods::getAvailableDefineVectorUpMethodsDisplayNames() const
512 {
513  std::map<QString, QString> names;
514  names[table] = "The operating table";
515  names[connectedFrameInP1] = "The connected frame in p1";
516  names[tool] = "The active tool";
517  return names;
518 }
519 
520 
521 std::vector<Transform3D> CustomMetric::calculateOrientations() const
522 {
523  std::vector<Vector3D> pos = this->getPositions();
524  Vector3D dir = this->getDirection();
525  Vector3D vup = this->getVectorUp();
526  Vector3D scale = this->getScale();
527 
528  std::vector<Transform3D> retval(pos.size());
529  for (unsigned i=0; i<retval.size(); ++i)
530  {
531  if (mTranslationOnly)
532  {
533  retval[i] = createTransformTranslate(pos[i]);
534  }
535  else
536  {
537  retval[i] = this->calculateOrientation(pos[i], dir, vup, scale);
538  }
539  }
540 
541  return retval;
542 }
543 
548 Transform3D CustomMetric::calculateOrientation(Vector3D pos, Vector3D dir, Vector3D vup, Vector3D scale) const
549 {
550  Transform3D R = this->calculateRotation(dir, vup);
551 
552  Transform3D center2DImage = this->calculateTransformTo2DImageCenter();
553 
556  Transform3D M = T*R*S*center2DImage;
557  return M;
558 }
559 
560 Transform3D CustomMetric::calculateTransformTo2DImageCenter() const
561 {
562  Transform3D position2DImage = Transform3D::Identity();
563  if(this->modelIsImage())
564  {
565  DataPtr model = this->getModel();
566  ImagePtr imageModel = boost::dynamic_pointer_cast<Image>(model);
567  vtkImageDataPtr vtkImage = imageModel->getBaseVtkImageData();
568  int xSize = vtkImage->GetExtent()[1] - vtkImage->GetExtent()[0];
569  int ySize = vtkImage->GetExtent()[3] - vtkImage->GetExtent()[2];
570  Eigen::Array3d spacing(vtkImage->GetSpacing());
571 
572  position2DImage = createTransformTranslate(Vector3D(-xSize*spacing[0]/2.0, -ySize*spacing[1]/2.0, 0));
573  }
574  return position2DImage;
575 }
576 
578 {
579  DataPtr model = this->getModel();
580 
581  return (model && model->getType() == "image");
582 }
583 
584 Transform3D CustomMetric::calculateRotation(Vector3D dir, Vector3D vup) const
585 {
586  Transform3D R = Transform3D::Identity();
587  bool directionAlongUp = similar(dot(vup, dir.normal()), 1.0);
588  if (!directionAlongUp)
589  {
590  Vector3D jvec = dir.normal();
591  Vector3D kvec = cross(vup, dir).normal();
592  Vector3D ivec = cross(jvec, kvec).normal();
593  Vector3D center = Vector3D::Zero();
594  R = createTransformIJC(ivec, jvec, center);
595 
596  Transform3D rotateY = cx::createTransformRotateY(M_PI_2);
597  R = R*rotateY;//Let the models X-axis align with patient X-axis
598 
599  if(this->modelIsImage())
600  {
601  Transform3D rotateX = cx::createTransformRotateX(M_PI_2);
602  R = R*rotateX;
603  }
604  }
605  return R;
606 }
607 
608 }
boost::shared_ptr< class SpaceProvider > SpaceProviderPtr
QString qstring_cast(const T &val)
void setOffsetFromP1(double val)
DoubleBoundingBox3D transform(const Transform3D &m, const DoubleBoundingBox3D &bb)
Transform3D createTransformRotateY(const double angle)
virtual Transform3D get_rMd() const
Definition: cxData.cpp:107
Vector3D topRight() const
void addXml(QDomNode &dataNode)
adds xml information about the data and its variabels
void setScaleToP1(bool val)
bool getTranslationOnly() const
Transform3D createTransformScale(const Vector3D &scale_)
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
void propertiesChanged()
emitted when one of the metadata properties (uid, name etc) changes
Vector3D getZeroPosition() const
void transformChanged()
emitted when transform is changed
boost::shared_ptr< class Image > ImagePtr
Definition: cxDicomWidget.h:48
void setDefineVectorUpMethod(QString defineVectorUpMethod)
Vector3D bottomLeft() const
void setDistanceMarkerVisibility(double val)
void updateTexture(MeshPtr model, Transform3D rMrr)
virtual void parseXml(QDomNode &dataNode)
Use a XML node to load data.
PatientModelServicePtr mDataManager
Definition: cxDataMetric.h:89
static CoordinateSystem reference()
SpaceProviderPtr mSpaceProvider
Definition: cxDataMetric.h:90
static DoubleBoundingBox3D fromCloud(std::vector< Vector3D > cloud)
virtual QString getType() const
Vector3D cross(const Vector3D &a, const Vector3D &b)
compute cross product of a and b.
Definition: cxVector3D.cpp:62
std::vector< Transform3D > calculateOrientations() const
void setTranslationOnly(bool val)
CustomMetric::DefineVectorUpMethods getDefineVectorUpMethods() const
boost::shared_ptr< class Data > DataPtr
QString getDefineVectorUpMethod() const
Transform3D createTransformIJC(const Vector3D &ivec, const Vector3D &jvec, const Vector3D &center)
bool getShowDistanceMarkers() const
void parseXml(QDomNode &dataNode)
Use a XML node to load data.
double getRepeatDistance() const
Data class that represents a custom.
void setOffsetFromP0(double val)
boost::shared_ptr< class PatientModelService > PatientModelServicePtr
virtual Vector3D getRefCoord() const
static CustomMetricPtr create(QString uid, QString name, PatientModelServicePtr dataManager, SpaceProviderPtr spaceProvider)
DataPtr getModel() const
Transform3D createTransformTranslate(const Vector3D &translation)
QString getSingleLineHeader() const
csTOOL_OFFSET
the tool space t with a virtual offset added along the z axis. (to)
double dot(const Vector3D &a, const Vector3D &b)
compute inner product (or dot product) of a and b.
Definition: cxVector3D.cpp:67
Representation of a floating-point bounding box in 3D. The data are stored as {xmin,xmax,ymin,ymax,zmin,zmax}, in order to simplify communication with vtk.
bool getTextureFollowTool() const
cxLogicManager_EXPORT SpaceProviderPtr spaceProvider()
Eigen::Vector3d Vector3D
Vector3D is a representation of a point or vector in 3D.
Definition: cxVector3D.h:63
bool similar(const CameraInfo &lhs, const CameraInfo &rhs, double tol)
void setModelUid(QString val)
RealScalar length() const
std::vector< Vector3D > getPointCloud() const
virtual DoubleBoundingBox3D boundingBox() const
double getOffsetFromP0() const
void setTextureFollowTool(bool val)
int getRepeatCount() const
void setShowDistanceMarkers(bool show)
Transform3D createTransformRotateX(const double angle)
bool modelIsImage() const
boost::shared_ptr< class Mesh > MeshPtr
vtkSmartPointer< class vtkImageData > vtkImageDataPtr
double getOffsetFromP1() const
double getDistanceMarkerVisibility() const
void setRepeatDistance(double val)
virtual QString getAsSingleLineString() const
boost::shared_ptr< class CustomMetric > CustomMetricPtr
virtual bool isValid() const
virtual void addXml(QDomNode &dataNode)
adds xml information about the data and its variabels
bool getScaleToP1() const
QString getModelUid() const