CustusX  16.12
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cxToolRep2D.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 
34 
35 #include "cxToolRep2D.h"
36 
37 #include <vtkRenderer.h>
38 #include <vtkActor2D.h>
39 #include <vtkTextProperty.h>
40 #include <vtkPolyDataMapper.h>
41 #include <vtkPolyData.h>
42 #include <vtkMatrix4x4.h>
43 #include "cxSliceProxy.h"
44 #include "cxTool.h"
45 #include "cxView.h"
46 
47 #include "cxTypeConversions.h"
48 #include "cxProbeSector.h"
49 #include "cxSpaceProvider.h"
50 #include "cxSettings.h"
51 
52 namespace cx
53 {
54 
55 ToolRep2D::ToolRep2D(SpaceProviderPtr spaceProvider) :
56  RepImpl(),
57  mSpaceProvider(spaceProvider),
58  m_vpMs(Transform3D::Identity()),
59  mBB_vp(0, 1, 0, 1, 0, 1),
60  mTooltipPointColor(0.96, 0.87, 0.17),
61  mOffsetPointColor(0.96, 0.87, 0.17),
62 // mTooltipLineColor(1, 0, 0),
63  mTooltipLineColor(0.25, 0.87, 0.16),
64  mOffsetLineColor(1.0, 0.8, 0.0),
65  mStipplePattern(0xffff)
66 {
67  mTooltipLineColor = settings()->value("View/tool2DColor").value<QColor>();
68  mTooltipPointColor = settings()->value("View/toolTipPointColor").value<QColor>();
69  mOffsetPointColor = settings()->value("View/toolOffsetPointColor").value<QColor>();
70  mOffsetLineColor = settings()->value("View/toolOffsetLineColor").value<QColor>();
71 
72  mUseOffset = true;
73  mUseCrosshair = false;
74  mUseToolLine = true;
75  mUseOffsetText = false;
76  mMergeOffsetAndToolLine = false;
77  mProbeSector.reset(new ProbeSector());
78  mProbeSectorPolyDataMapper = vtkPolyDataMapperPtr::New();
79  mProbeSectorActor = vtkActorPtr::New();
80 }
81 
83 {
84 }
85 
86 ToolRep2DPtr ToolRep2D::New(SpaceProviderPtr spaceProvider, const QString& uid)
87 {
88  return wrap_new(new ToolRep2D(spaceProvider), uid);
89 }
90 
91 QString ToolRep2D::getType() const
92 {
93  return "vm::ToolRep2D";
94 }
95 
96 double ToolRep2D::getOffset()
97 {
98  if (mSlicer->getTool() && showOffset())
99  return mSlicer->getTool()->getTooltipOffset();
100  return 0.0;
101 }
102 
107 {
108  if (similar(m_vpMs, vpMs) && similar(mBB_vp, vp))
109  return;
110 
111  m_vpMs = vpMs;
112  mBB_vp = vp;
113 
114  crossHairResized();
115  this->setModified();
116 }
117 
121 {
122  if (mSlicer)
123  {
124  disconnect(mSlicer.get(), SIGNAL(transformChanged(Transform3D)), this, SLOT(sliceTransformChangedSlot(Transform3D)));
125  disconnect(mSlicer.get(), SIGNAL(toolTransformAndTimestamp(Transform3D,double)), this, SLOT(toolTransformAndTimestampSlot(Transform3D,double)));
126  disconnect(mSlicer.get(), SIGNAL(toolVisible(bool)), this, SLOT(toolVisibleSlot(bool)));
127  }
128 
129  mSlicer = slicer;
130 
131  connect(mSlicer.get(), SIGNAL(transformChanged(Transform3D)), this, SLOT(sliceTransformChangedSlot(Transform3D)));
132  connect(mSlicer.get(), SIGNAL(toolTransformAndTimestamp(Transform3D,double)), this, SLOT(toolTransformAndTimestampSlot(Transform3D,double)));
133  connect(mSlicer.get(), SIGNAL(toolVisible(bool)), this, SLOT(toolVisibleSlot(bool)));
134 }
135 
139 {
140  if (mUseOffset==on)
141  return;
142  mUseOffset = on;
143  setVisibility();
144 }
145 
149 {
150  if (mUseCrosshair==on)
151  return;
152  mUseCrosshair = on;
153  setVisibility();
154 }
155 
159 {
160  if (mUseToolLine==on)
161  return;
162  mUseToolLine = on;
163  setVisibility();
164 }
165 
169 {
170  if (mUseOffsetText==on)
171  return;
172  mUseOffsetText = on;
173  setVisibility();
174 }
175 
181 {
182  if (mMergeOffsetAndToolLine==on)
183  return;
184  mMergeOffsetAndToolLine = on;
185  setVisibility();
186 }
187 
189 {
190  createToolLine(view->getRenderer(), Vector3D(0,0,0));
191  createCrossHair(view->getRenderer() );
192  createOffsetText(view->getRenderer(), Vector3D(0,0,0));
193  view->getRenderer()->AddActor(mProbeSectorActor);
194  setVisibility();
195  this->setModified();
196 }
197 
199 {
200  cursor.reset();
201  center2Tool.reset();
202  tool2Back.reset();
203  centerPoint.reset();
204  toolPoint.reset();
205  distanceText.reset();
206  view->getRenderer()->RemoveActor(mProbeSectorActor);
207 }
208 
209 void ToolRep2D::sliceTransformChangedSlot(Transform3D sMr)
210 {
211  this->setModified();
212 }
213 
214 void ToolRep2D::toolTransformAndTimestampSlot(Transform3D prMt, double timestamp)
215 {
216  this->setModified();
217 }
218 
219 void ToolRep2D::toolVisibleSlot(bool visible)
220 {
221  setVisibility();
222  this->setModified();
223 }
224 
226 {
227  this->update();
228 }
229 
230 void ToolRep2D::update()
231 {
232  if (!mSlicer->getTool())
233  return;
234 
235  Transform3D prMt = Transform3D::Identity();
236  if (mSlicer->getTool())
237  {
238  prMt = mSlicer->getTool()->get_prMt();
239  }
240  Transform3D rMpr = mSpaceProvider->get_rMpr();
241  Transform3D sMr = mSlicer->get_sMr();
242  Transform3D sMt = sMr*rMpr*prMt;
243  Transform3D vpMt = m_vpMs*sMt;
244 
245  // only show probe if aligned with the slice plane:
246  double dotted = dot(Vector3D(0,0,1),sMt.vector(Vector3D(1,0,0)));
247  bool aligned = similar(fabs(dotted), 1.0, 0.1);
248  if (this->showProbe() && aligned)
249  {
251 
252  mProbeSector->setData(mSlicer->getTool()->getProbe()->getProbeDefinition());
253  Transform3D tMu = mProbeSector->get_tMu();
254  mProbeSectorPolyDataMapper->SetInputData(mProbeSector->getSectorLinesOnly());
255  if (mProbeSectorPolyDataMapper->GetInput())
256  {
257  mProbeSectorActor->SetMapper(mProbeSectorPolyDataMapper);
258  }
259  mProbeSectorActor->SetUserMatrix((T*sMt*tMu).getVtkMatrix());
260  mProbeSectorActor->SetVisibility(mSlicer->getTool()->getVisible());
261  }
262  else
263  {
264  mProbeSectorActor->SetVisibility(false);
265  }
266 
267  Vector3D cross = vpMt.coord(getOffset() * Vector3D(0,0,1)); // zero position plus offset along z
268  Vector3D tooltip = vpMt.coord(Vector3D(0,0,0)); // the zero position
269  Vector3D toolback = vpMt.coord(Vector3D(0,0,-1000)); // a point 1m backwards in z
270 
271  if (cursor)
272  {
273  cursor->update(cross, mBB_vp);
274  }
275  updateOffsetText();
276  updateToolLine(cross, tooltip, toolback);
277 }
278 
280 {
281  return mSlicer->getTool() && mSlicer->getTool()->hasType(Tool::TOOL_US_PROBE);
282 }
284 {
285  return mSlicer->getTool() && mUseOffset;
286 }
287 
288 void ToolRep2D::setVisibility()
289 {
290 // Logger::log("vm.log", "ToolRep2D::setVisibility(), offset=" + string_cast(showOffset()));
291  bool hasTool = mSlicer->getTool() ? true : false;
292 
293  if (cursor)
294  cursor->getActor()->SetVisibility(mUseCrosshair && hasTool);
295  if (center2Tool)
296  center2Tool->getActor()->SetVisibility(showOffset());
297  if (tool2Back)
298  tool2Back->getActor()->SetVisibility(mUseToolLine && hasTool);
299  if (centerPoint)
300  centerPoint->getActor()->SetVisibility(mUseToolLine && hasTool);
301  if (centerPoint)
302  centerPoint->getActor()->SetVisibility(showOffset() && !mMergeOffsetAndToolLine);
303  if (distanceText)
304  distanceText->getActor()->SetVisibility(mUseOffsetText && showOffset() && !mMergeOffsetAndToolLine);
305 }
306 
310 void ToolRep2D::createCrossHair(vtkRendererPtr renderer)
311 {
312  //Logger::log("vm.log", "<"+string_cast(__FUNCTION__)+">"+" new " );
313  cursor.reset( new CrossHair2D(renderer) ) ;
314  crossHairResized();
315 }
316 
320 void ToolRep2D::crossHairResized()
321 {
322  if (cursor)
323  {
324  double bordarOffset = 30.0;
325  QColor col = settings()->value("View/toolCrossHairColor").value<QColor>();
326 // RGBColor color(1.0, 0.8, 0.0);
327  RGBColor color(col.redF(), col.greenF(), col.blueF());
328 // RGBColor color(1.0, 0.2, 0.0);
329  Vector3D focalPoint(0.0,0.0,0.0);
330  //Logger::log("tool.log", "("+string_cast(__FUNCTION__)+")"+" mCross"+string_cast(cross));
331  //cursor->setValue( focalPoint, mBB_vp.range()[0], mBB_vp.range()[1], bordarOffset, color );
332  cursor->setValue( focalPoint, int(mBB_vp.range()[0]), int(mBB_vp.range()[1]), bordarOffset, color );
333  }
334 }
335 
338 void ToolRep2D::createToolLine(vtkRendererPtr renderer, const Vector3D& centerPos )
339 {
340  // line from tooltip to offset point
341  center2Tool.reset(new LineSegment(renderer));
342  center2Tool->setPoints(centerPos, Vector3D(0.0, 0.0, 0.0), mOffsetLineColor, mStipplePattern);
343  center2Tool->setWidth(2);
344 
345  // line from back infinity to tooltip
346  tool2Back.reset(new LineSegment(renderer));
347  tool2Back->setPoints(Vector3D(0.0, 0.0, 0.0), Vector3D(0.0, 0.0, 0.0), mTooltipLineColor);
348  tool2Back->setWidth(2);
349 
350  // Add dot at offset point
351  centerPoint.reset(new OffsetPoint(renderer));
352  centerPoint->setValue(centerPos, mOffsetPointColor);
353  centerPoint->setRadius(4);
354  centerPoint->getActor()->VisibilityOff();
355 
356  // Add dot at tooltip point
357  toolPoint.reset(new OffsetPoint(renderer));
358  toolPoint->setValue(Vector3D(0.0, 0.0, 0.0), mTooltipPointColor);
359  toolPoint->setRadius(3);
360 }
361 
364 void ToolRep2D::createOffsetText(vtkRendererPtr renderer, const Vector3D& pos )
365 {
366  QColor color = QColor::fromRgbF(0.7372, 0.815, 0.6039);
367  distanceText.reset( new TextDisplay( "---", color, 18) );
368  distanceText->getActor()->GetPositionCoordinate()->SetCoordinateSystemToNormalizedViewport();
369  distanceText->textProperty()->SetJustificationToRight();
370  distanceText->setPosition(Vector3D(0.95, 0.95, 0.0));
371  renderer->AddActor( distanceText->getActor() );
372  updateOffsetText();
373 }
374 
379 void ToolRep2D::updateToolLine(const Vector3D& crossPos, const Vector3D& toolTipPos, const Vector3D toolTipBackPos)
380 {
381  if (!center2Tool || !tool2Back || !centerPoint || !toolPoint)
382  return;
383 
384  if (mMergeOffsetAndToolLine) // for ACS only
385  {
386  // Make entire line look like an offset line, since tooltip point will become projected
387  // into the planes set by the offset position, which may be seen as navigation error.
388  center2Tool->getActor()->SetVisibility(false);
389  tool2Back->updatePosition(crossPos, toolTipBackPos);
390  if (getOffset() > 0.01)
391  {
392  toolPoint->getActor()->SetVisibility(false);
393  centerPoint->getActor()->SetVisibility(true);
394  tool2Back->setColor(mOffsetLineColor);
395  tool2Back->setPattern(mStipplePattern);
396  }
397  else
398  {
399  toolPoint->getActor()->SetVisibility(true);
400  centerPoint->getActor()->SetVisibility(false);
401  tool2Back->setColor(mTooltipLineColor);
402  tool2Back->setPattern(0xffff);
403  }
404  }
405  else
406  {
407  center2Tool->updatePosition(crossPos, toolTipPos);
408  tool2Back->updatePosition(toolTipPos, toolTipBackPos);
409  if (getOffset() > 0.01)
410  {
411  centerPoint->getActor()->SetVisibility(true);
412  }
413  else
414  {
415  centerPoint->getActor()->SetVisibility(false);
416  }
417  }
418  centerPoint->update(crossPos);
419  toolPoint->update(toolTipPos);
420 }
421 
422 void ToolRep2D::updateOffsetText()
423 {
424  if (!distanceText)
425  {
426  return;
427  }
428  if (getOffset() > 2.0 && mUseOffsetText && showOffset())
429  {
430  distanceText->updateText("Offset: " + QString::number(getOffset(), 'g', 3) + " mm");
431  distanceText->getActor()->VisibilityOn();
432  }
433  else
434  {
435  distanceText->getActor()->VisibilityOff(); // doesnt work...
436  distanceText->updateText( "" ); // does work...
437  }
438 }
439 
440 } // namespace vm
boost::shared_ptr< class SpaceProvider > SpaceProviderPtr
virtual QString getType() const
Definition: cxToolRep2D.cpp:91
void setUseOffsetText(bool on)
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
boost::shared_ptr< class SliceProxy > SliceProxyPtr
static boost::shared_ptr< REP > wrap_new(REP *object, QString uid)
Definition: cxRepImpl.h:83
virtual void removeRepActorsFromViewRenderer(ViewPtr view)
virtual void onModifiedStartRender()
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
Definition: cxSettings.cpp:87
virtual void addRepActorsToViewRenderer(ViewPtr view)
boost::shared_ptr< class View > ViewPtr
void setSliceProxy(SliceProxyPtr slicer)
boost::shared_ptr< class ToolRep2D > ToolRep2DPtr
Vector3D cross(const Vector3D &a, const Vector3D &b)
compute cross product of a and b.
Definition: cxVector3D.cpp:62
Display a Tool in 2D.
Definition: cxToolRep2D.h:67
vtkMatrix4x4Ptr getVtkMatrix(const Eigen::Affine3d *self)
vtkSmartPointer< class vtkRenderer > vtkRendererPtr
void setMergeOffsetAndToolLine(bool on)
Transform3D createTransformTranslate(const Vector3D &translation)
void setUseToolLine(bool on)
double dot(const Vector3D &a, const Vector3D &b)
compute inner product (or dot product) of a and b.
Definition: cxVector3D.cpp:67
Settings * settings()
Shortcut for accessing the settings instance.
Definition: cxSettings.cpp:42
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.
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 setUseCrosshair(bool on)
void setUseOffset(bool on)
static ToolRep2DPtr New(SpaceProviderPtr spaceProvider, const QString &uid="")
Definition: cxToolRep2D.cpp:86
Ultrasond probe. The tool has a Probe subinterface with a sector and a video stream.
Definition: cxTool.h:108
void setViewportData(const Transform3D &vpMs, const DoubleBoundingBox3D &vp)
void setModified()
Definition: cxRepImpl.cpp:133