Fraxinus  17.12-rc4
An IGT application
cxRegistrationTransform.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 
35 //#include <QtXML>
36 #include <QDomElement>
37 #include "cxTime.h"
38 #include "cxTypeConversions.h"
39 #include "cxLogger.h"
40 
41 namespace cx
42 {
43 
44 // --------------------------------------------------------
45 RegistrationHistoryPtr RegistrationHistory::mNull;
46 // --------------------------------------------------------
47 
48 
52 {
53 public:
54  virtual void addXml(QDomNode& parentNode) const
55  {
56  }
57  virtual void parseXml(QDomNode& dataNode)
58  {
59  }
60 
62  {
63  }
64  virtual void setRegistration(const Transform3D& transform)
65  {
66  }
67  virtual void addOrUpdateRegistration(const QDateTime& oldTime, const RegistrationTransform& newTransform)
68  {
69  }
70 
71  virtual void setParentSpace(const QString& newParent)
72  {
73  }
74  virtual void addParentSpace(const QString& newParent)
75  {
76  }
77  virtual void addParentSpace(const ParentSpace& newParent)
78  {
79  }
80  virtual void updateParentSpace(const QDateTime& oldTime, const ParentSpace& newParent)
81  {
82  }
83 
84  virtual std::vector<RegistrationTransform> getData() const
85  {
86  return std::vector<RegistrationTransform>();
87  }
88  virtual std::vector<ParentSpace> getParentSpaces() const
89  {
90  return std::vector<ParentSpace>();
91  }
92  virtual void removeNewerThan(const QDateTime& timestamp)
93  {
94  }
95  virtual void setActiveTime(const QDateTime& timestamp)
96  {
97  }
98  virtual QDateTime getActiveTime() const
99  {
100  return QDateTime();
101  }
103  {
104  return RegistrationTransform();
105  }
107  {
108  return ParentSpace();
109  }
110  virtual void clear()
111  {
112  }
113  virtual bool isNull() const
114  {
115  return true;
116  }
117 };
118 
119 //---------------------------------------------------------
120 //------- RegistrationTransform -------------------------
121 //---------------------------------------------------------
122 
124  mValue(Transform3D::Identity()), mTemp(false)
125 {
126 }
127 
128 RegistrationTransform::RegistrationTransform(const Transform3D& value, const QDateTime& timestamp, const QString& type, bool tempTransform)
129 {
130  mValue = value;
131  mTimestamp = timestamp;
132  mType = type;
133  mTemp = tempTransform;
134 }
135 
136 void RegistrationTransform::addXml(QDomNode& parentNode) const
137 {
138  QDomDocument doc = parentNode.ownerDocument();
139  QDomElement base = doc.createElement("registrationTransform");
140  parentNode.appendChild(base);
141 
142  base.setAttribute("timestamp", mTimestamp.toString(timestampSecondsFormat()));
143  base.setAttribute("type", mType);
144 
145  if (!mFixed.isEmpty())
146  base.setAttribute("fixed", mFixed);
147  if (!mMoving.isEmpty())
148  base.setAttribute("moving", mMoving);
149 
150  base.appendChild(doc.createTextNode("\n" + qstring_cast(mValue)));
151 }
152 
153 void RegistrationTransform::parseXml(QDomNode& dataNode)
154 {
155  if (dataNode.isNull())
156  return;
157 
158  QDomElement base = dataNode.toElement();
159 
160  mTimestamp = QDateTime::fromString(base.attribute("timestamp"), timestampSecondsFormat());
161  mType = base.attribute("type");
162  mValue = Transform3D::fromString(base.text());
163  mFixed = base.attribute("fixed");
164  mMoving = base.attribute("moving");
165 }
166 
168 {
169  return lhs.mTimestamp < rhs.mTimestamp;
170 }
171 
173 {
174  return similar(lhs.mValue, rhs.mValue, 1.0E-3) && (lhs.mTimestamp == rhs.mTimestamp) && (lhs.mType == rhs.mType);
175 }
176 
177 //---------------------------------------------------------
178 //------- RegistrationTransform -------------------------
179 //---------------------------------------------------------
180 
182 {
183 
184 }
185 
186 ParentSpace::ParentSpace(const QString& uid, const QDateTime& timestamp, const QString& type)
187 {
188  mUid = uid;
189  mTimestamp = timestamp;
190  mType = type;
191 }
192 
193 void ParentSpace::addXml(QDomNode& parentNode) const
194 {
195  QDomDocument doc = parentNode.ownerDocument();
196  QDomElement base = doc.createElement("parentFrame");
197  parentNode.appendChild(base);
198 
199  base.setAttribute("value", mUid);
200  base.setAttribute("timestamp", mTimestamp.toString(timestampSecondsFormat()));
201  base.setAttribute("type", mType);
202 }
203 
204 void ParentSpace::parseXml(QDomNode& dataNode)
205 {
206  if (dataNode.isNull())
207  return;
208 
209  QDomElement base = dataNode.toElement();
210 
211  mTimestamp = QDateTime::fromString(base.attribute("timestamp"), timestampSecondsFormat());
212  mType = base.attribute("type");
213  mUid = base.attribute("value");
214 }
215 
216 bool operator<(const ParentSpace& lhs, const ParentSpace& rhs)
217 {
218  return lhs.mTimestamp < rhs.mTimestamp;
219 }
220 
221 bool operator==(const ParentSpace& lhs, const ParentSpace& rhs)
222 {
223  return (lhs.mUid == rhs.mUid) && (lhs.mTimestamp == rhs.mTimestamp) && (lhs.mType == rhs.mType);
224 }
225 
226 //---------------------------------------------------------
227 //------- RegistrationHistory -------------------------
228 //---------------------------------------------------------
229 
231 {
232  if (!mNull)
233  mNull.reset(new RegistrationHistoryNull);
234  return mNull;
235 }
236 
237 void RegistrationHistory::addXml(QDomNode& parentNode) const
238 {
239  QDomDocument doc = parentNode.ownerDocument();
240  QDomElement base = doc.createElement("registrationHistory");
241  parentNode.appendChild(base);
242 
243  QDomElement currentTime = doc.createElement("currentTime");
244  currentTime.appendChild(doc.createTextNode(mCurrentTime.toString(timestampSecondsFormat())));
245  base.appendChild(currentTime);
246 
247  for (unsigned i = 0; i < mData.size(); ++i)
248  {
249  mData[i].addXml(base);
250  }
251  for (unsigned i = 0; i < mParentSpaces.size(); ++i)
252  {
253  mParentSpaces[i].addXml(base);
254  }
255 }
256 
257 void RegistrationHistory::parseXml(QDomNode& dataNode)
258 {
259  if (dataNode.isNull())
260  return;
261 
262  mData.clear();
263  QString currentTimeRaw = dataNode.namedItem("currentTime").toElement().text();
264  QDateTime currentTime = QDateTime::fromString(currentTimeRaw, timestampSecondsFormat());
265 
266  // iterate over all data elements
267  QDomElement currentElem = dataNode.firstChildElement("registrationTransform");
268  for (; !currentElem.isNull(); currentElem = currentElem.nextSiblingElement("registrationTransform"))
269  {
271  transform.parseXml(currentElem);
272  mData.push_back(transform);
273  }
274 
275  // iterate over all data elements
276  currentElem = dataNode.firstChildElement("parentFrame");
277  for (; !currentElem.isNull(); currentElem = currentElem.nextSiblingElement("parentFrame"))
278  {
280  transform.parseXml(currentElem);
281  mParentSpaces.push_back(transform);
282  }
283 
284  std::sort(mData.begin(), mData.end());
285  std::sort(mParentSpaces.begin(), mParentSpaces.end());
286  setActiveTime(currentTime); // update cache
287 }
288 
290 {
291  mData.clear();
292  mCurrentTime = QDateTime();
293  mTransformCache = RegistrationTransform();
294 }
295 
300 void RegistrationHistory::addRegistrationInternal(const RegistrationTransform& transform)
301 {
302  if (std::count(mData.begin(), mData.end(), transform)) // ignore if already present
303  return;
304 
305  mData.push_back(transform);
306  std::sort(mData.begin(), mData.end());
307 
308  bool silent = transform.mTemp;
309  this->blockSignals(silent);
310  setActiveTime(QDateTime()); // reset to last registration when reregistering.
311  this->blockSignals(false);
312 }
313 
320 void RegistrationHistory::addOrUpdateRegistration(const QDateTime& oldTime, const RegistrationTransform& newTransform)
321 {
322  for (std::vector<RegistrationTransform>::iterator iter = mData.begin(); iter != mData.end(); ++iter)
323  {
324  if ((iter->mTimestamp == oldTime)
325  && oldTime.isValid()
326  && iter->mTemp)
327  {
328  mData.erase(iter);
329  break;
330  }
331  }
332  this->addRegistrationInternal(newTransform);
333 }
334 
339 {
340  bool changed = true;
341  if (similar(getCurrentRegistration().mValue, transform))
342  {
343  changed = false;
344  }
345  mData.clear();
346  this->addRegistrationInternal(RegistrationTransform(transform));
347  if (changed)
348  {
349  emit currentChanged();
350  }
351 }
352 
356 void RegistrationHistory::setParentSpace(const QString& newParent)
357 {
358  mParentSpaces.clear();
359  this->addParentSpace(ParentSpace(newParent));
360 }
361 
362 void RegistrationHistory::addParentSpace(const QString& newParent)
363 {
364  this->addParentSpace(ParentSpace(newParent, QDateTime::currentDateTime(), "Set Parent Frame"));
365 }
366 
368 {
369  for (int i = 0; i < mParentSpaces.size(); ++i)
370  {
371  if(mParentSpaces[i].mUid == newParent.mUid)
372  return;// ignore if already present
373  }
374 
375  mParentSpaces.push_back(newParent);
376  std::sort(mParentSpaces.begin(), mParentSpaces.end());
377  setActiveTime(QDateTime()); // reset to last registration when reregistering.
378 }
379 
380 void RegistrationHistory::updateParentSpace(const QDateTime& oldTime, const ParentSpace& newParent)
381 {
382  for (std::vector<ParentSpace>::iterator iter = mParentSpaces.begin(); iter != mParentSpaces.end(); ++iter)
383  {
384  if (iter->mTimestamp != oldTime)
385  continue;
386  mParentSpaces.erase(iter);
387  break;
388  }
389  this->addParentSpace(newParent);
390 }
391 
393 {
394  return mParentSpaceCache;
395 }
396 
397 std::vector<RegistrationTransform> RegistrationHistory::getData() const
398 {
399  return mData;
400 }
401 
402 std::vector<ParentSpace> RegistrationHistory::getParentSpaces() const
403 {
404  return mParentSpaces;
405 }
406 
407 void RegistrationHistory::removeNewerThan(const QDateTime& timestamp)
408 {
409  if (!timestamp.isValid())
410  return;
411 
412  for (std::vector<RegistrationTransform>::iterator iter = mData.begin(); iter != mData.end();)
413  {
414  if (iter->mTimestamp > timestamp)
415  {
416  std::cout << "RegistrationHistory::removeNewerThan(" << timestamp.toString(timestampSecondsFormatNice())
417  << "): removed [" << iter->mTimestamp.toString(timestampSecondsFormatNice()) << ", " << iter->mType
418  << "]" << std::endl;
419  iter = mData.erase(iter);
420  }
421  else
422  {
423  ++iter;
424  }
425  }
426 
427  for (std::vector<ParentSpace>::iterator iter = mParentSpaces.begin(); iter != mParentSpaces.end();)
428  {
429  if (iter->mTimestamp > timestamp)
430  {
431  std::cout << "RegistrationHistory::removeNewerThan(" << timestamp.toString(timestampSecondsFormatNice())
432  << "): removed parent frame [" << iter->mTimestamp.toString(timestampSecondsFormatNice()) << ", "
433  << iter->mType << "]" << std::endl;
434  iter = mParentSpaces.erase(iter);
435  }
436  else
437  {
438  ++iter;
439  }
440  }
441 
442  setActiveTime(QDateTime());
443 }
444 
445 void RegistrationHistory::setCache(const RegistrationTransform& val, const ParentSpace& parent,
446  const QDateTime& timestamp)
447 {
448  if ((mTransformCache == val) && (mParentSpaceCache == parent) && (mCurrentTime == timestamp))
449  return;
450 
451  mCurrentTime = timestamp;
452  mTransformCache = val;
453  mParentSpaceCache = parent;
454 
455  emit currentChanged();
456 }
457 
461 void RegistrationHistory::setActiveTime(const QDateTime& timestamp)
462 {
464  ParentSpace parent;
465  // set to specified time
466  if (timestamp.isValid())
467  {
468  for (std::vector<RegistrationTransform>::iterator iter = mData.begin(); iter != mData.end(); ++iter)
469  {
470  if (iter->mTimestamp <= timestamp)
471  val = *iter;
472  }
473  for (std::vector<ParentSpace>::iterator iter = mParentSpaces.begin(); iter != mParentSpaces.end(); ++iter)
474  {
475  if (iter->mTimestamp <= timestamp)
476  parent = *iter;
477  }
478  }
479  else
480  {
481  if (!mData.empty())
482  val = mData.back();
483  if (!mParentSpaces.empty())
484  parent = mParentSpaces.back();
485  }
486 
487  setCache(val, parent, timestamp);
488 }
489 
491 {
492  return mCurrentTime;
493 }
494 
496 {
497  return mTransformCache;
498 }
499 
500 } // end namespace cx
501 
QString qstring_cast(const T &val)
virtual void setRegistration(const Transform3D &transform)
bool operator<(const Landmark &lhs, const Landmark &rhs)
Definition: cxLandmark.cpp:94
virtual std::vector< RegistrationTransform > getData() const
virtual void setParentSpace(const QString &newParent)
DoubleBoundingBox3D transform(const Transform3D &m, const DoubleBoundingBox3D &bb)
virtual ParentSpace getCurrentParentSpace()
boost::shared_ptr< class RegistrationHistory > RegistrationHistoryPtr
Definition: cxDataManager.h:58
Definition of a parent space event.
virtual void addXml(QDomNode &parentNode) const
write internal state to node
static RegistrationHistoryPtr getNullObject()
virtual void setParentSpace(const QString &newParent)
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
virtual void addOrUpdateRegistration(const RegistrationTransform &transform)
QString timestampSecondsFormatNice()
Definition: cxTime.cpp:47
virtual void updateParentSpace(const QDateTime &oldTime, const ParentSpace &newParent)
virtual void setActiveTime(const QDateTime &timestamp)
virtual QDateTime getActiveTime() const
QString timestampSecondsFormat()
Definition: cxTime.cpp:39
QString mUid
parent frame uid
virtual void clear()
reset all data loaded from xml
virtual void addXml(QDomNode &parentNode) const
write internal state to node
virtual std::vector< ParentSpace > getParentSpaces() const
QDateTime mTimestamp
time the transform was registrated.
virtual void addParentSpace(const QString &newParent)
QDateTime mTimestamp
time the transform was registrated.
void parseXml(QDomNode &dataNode)
read internal state from node
virtual std::vector< RegistrationTransform > getData() const
Transform3D mValue
value of transform
void addXml(QDomNode &parentNode) const
write internal state to node
virtual QDateTime getActiveTime() const
virtual RegistrationTransform getCurrentRegistration() const
virtual void removeNewerThan(const QDateTime &timestamp)
QString mType
description of the kind if registration (manual, patient, landmark, coregistration etc) ...
void parseXml(QDomNode &dataNode)
read internal state from node
QString mType
description of the kind if registration (manual, patient, landmark, coregistration etc) ...
virtual void removeNewerThan(const QDateTime &timestamp)
virtual ParentSpace getCurrentParentSpace()
A registration event and its transform.
virtual void clear()
reset all data loaded from xml
virtual void updateParentSpace(const QDateTime &oldTime, const ParentSpace &newParent)
bool operator==(const RegistrationTransform &lhs, const RegistrationTransform &rhs)
bool similar(const CameraInfo &lhs, const CameraInfo &rhs, double tol)
virtual RegistrationTransform getCurrentRegistration() const
virtual std::vector< ParentSpace > getParentSpaces() const
virtual void parseXml(QDomNode &dataNode)
read internal state from node
virtual void parseXml(QDomNode &dataNode)
read internal state from node
virtual void addOrUpdateRegistration(const QDateTime &oldTime, const RegistrationTransform &newTransform)
virtual void addOrUpdateRegistration(const QDateTime &oldTime, const RegistrationTransform &newTransform)
virtual void setActiveTime(const QDateTime &timestamp)
virtual void addParentSpace(const ParentSpace &newParent)
virtual void addParentSpace(const QString &newParent)
void addXml(QDomNode &parentNode) const
write internal state to node
virtual void setRegistration(const Transform3D &transform)
A history of registration events.
Namespace for all CustusX production code.