CustusX  2023.01.05-dev+develop.0da12
An IGT application
cxInteractiveCropper.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) SINTEF Department of Medical Technology.
5 All rights reserved.
6 
7 CustusX is released under a BSD 3-Clause license.
8 
9 See Lisence.txt (https://github.com/SINTEFMedtek/CustusX/blob/master/License.txt) for details.
10 =========================================================================*/
11 
12 /*
13  * cxInteractiveCropper.cpp
14  *
15  * \date Aug 24, 2010
16  * \author christiana
17  */
18 #include "cxInteractiveCropper.h"
19 
20 #include "cxView.h"
21 
22 #include <vector>
23 #include <vtkTransform.h>
24 #include <vtkAbstractVolumeMapper.h>
25 #include <vtkVolumeMapper.h>
26 #include <vtkRenderWindow.h>
27 #include <vtkRenderer.h>
28 #include <vtkImageData.h>
29 #include <vtkCommand.h>
30 #include <vtkBoxWidget2.h>
31 #include <vtkBoxWidget.h>
32 #include "cxTypeConversions.h"
33 #include "cxBoundingBox3D.h"
34 #include "cxImage.h"
35 #include "cxTransform3D.h"
36 #include "cxVolumetricRep.h"
37 
38 #include "cxActiveImageProxy.h"
39 #include "cxActiveData.h"
40 
41 namespace cx
42 {
43 
44 class CropBoxCallback: public vtkCommand
45 {
46 public:
48  {
49  }
50  static CropBoxCallback* New()
51  {
52  return new CropBoxCallback;
53  }
55  {
56  mCropper = cropper;
57  }
58  virtual void Execute(vtkObject* caller, unsigned long, void*)
59  {
60  DoubleBoundingBox3D bb_new = mCropper->getBoxWidgetSize();
61  mCropper->setCroppingRegion(bb_new);
62  }
64 };
65 
66 class CropBoxEnableCallback: public vtkCommand
67 {
68 public:
69  CropBoxEnableCallback() : mCropper(NULL), mValue(false)
70  {
71  }
73  {
74  return new CropBoxEnableCallback;
75  }
76  void SetCropper(bool val, InteractiveCropper* cropper)
77  {
78  mValue = val;
79  mCropper = cropper;
80  }
81  virtual void Execute(vtkObject* caller, unsigned long, void*)
82  {
83  DoubleBoundingBox3D bb_new = mCropper->getBoxWidgetSize();
84  mCropper->boxWasShown(mValue);
85  }
86  bool mValue;
88 };
89 
90 //---------------------------------------------------------
91 //---------------------------------------------------------
92 //---------------------------------------------------------
93 
94 
96  mActiveData(activeData)
97 {
98  mActiveImageProxy = ActiveImageProxy::New(mActiveData);
99  connect(mActiveImageProxy.get(), &ActiveImageProxy::activeImageChanged, this, &InteractiveCropper::imageChangedSlot);
100  connect(mActiveImageProxy.get(), SIGNAL(cropBoxChanged()), this, SLOT(imageCropChangedSlot()));
101 }
102 
103 void InteractiveCropper::initialize()
104 {
105  if (mBoxWidget) // already initialized
106  return;
107 
108  mBoxWidget = vtkBoxWidgetPtr::New();
109  mBoxWidget->RotationEnabledOff();
110 
111  double bb_hard[6] =
112  { -1, 1, -1, 1, -1, 1 };
113  mBoxWidget->PlaceWidget(bb_hard);
114 
115  mCropBoxCallback = CropBoxCallbackPtr::New();
116  mCropBoxCallback->SetCropper(this);
117  mCropBoxEnableCallback = CropBoxEnableCallbackPtr::New();
118  mCropBoxEnableCallback->SetCropper(true, this);
119  mCropBoxDisableCallback = CropBoxEnableCallbackPtr::New();
120  mCropBoxDisableCallback->SetCropper(false, this);
121 
122  mBoxWidget->SetInteractor(mView->getRenderWindow()->GetInteractor());
123 
124  mBoxWidget->SetEnabled(false);
125 }
126 
128 {
129  mView = view;
130  this->updateBoxWidgetInteractor();
131 }
132 
133 void InteractiveCropper::updateBoxWidgetInteractor()
134 {
135  if (!mView)
136  return;
137 
138  this->initialize();
139 
140  if (this->getUseCropping())
141  {
142  mBoxWidget->SetInteractor(mView->getRenderWindow()->GetInteractor());
143  mBoxWidget->AddObserver(vtkCommand::InteractionEvent, mCropBoxCallback);
144  mBoxWidget->AddObserver(vtkCommand::EnableEvent, mCropBoxEnableCallback);
145  mBoxWidget->AddObserver(vtkCommand::DisableEvent, mCropBoxDisableCallback);
146  }
147  else
148  {
149  mBoxWidget->RemoveObserver(vtkCommand::InteractionEvent);
150  mBoxWidget->RemoveObserver(vtkCommand::EnableEvent);
151  mBoxWidget->RemoveObserver(vtkCommand::DisableEvent);
152  }
153 }
154 
156 {
157  if (!mImage)
158  return;
159  if (!mBoxWidget)
160  return;
161  if (this->getShowBoxWidget() == on)
162  return;
163 
164  //Turn on cropping if not on to save user from pressing two boxes
165  if (!mImage->getCropping() && on)
166  this->useCropping(true);
167 
168  mBoxWidget->SetEnabled(on);
169  emit changed();
170 }
171 
175 {
176  if (!mImage || !mBoxWidget)
177  return DoubleBoundingBox3D(0,0,0,0,0,0);
178  return mImage->getCroppingBox();
179 }
180 
182 {
183  this->setCroppingRegion(bb_d);
184  this->setBoxWidgetSize(bb_d);
185 }
186 
188 {
189  if (this->getUseCropping() == on)
190  return;
191 
192  if (!mImage)
193  return;
194 
195  mImage->setCropping(on);
196 }
197 
198 void InteractiveCropper::imageCropChangedSlot()
199 {
200  if (!mImage)
201  return;
202 
203  DoubleBoundingBox3D bb_d = this->getBoundingBox();
204  this->setBoxWidgetSize(bb_d);
205  this->updateBoxWidgetInteractor();
206 
207  if (!mImage->getCropping())
208  this->showBoxWidget(false);
209 
210  emit changed();
211 }
212 
214 {
215  emit changed();
216 }
217 
218 void InteractiveCropper::imageChangedSlot()
219 {
220 // mImage = mPatientModelService->getActiveImage();
221  mImage = mActiveData->getActive<Image>();
222 
223  this->imageCropChangedSlot();
224  emit changed();
225 }
226 
228 {
229  if (!mImage)
230  return false;
231  return mImage->getCropping();
232 }
233 
235 {
236  if (!mBoxWidget)
237  return false;
238  return mBoxWidget->GetEnabled();
239 }
240 
242 {
243  std::vector<int> dimensions;
244  if(!mImage)
245  return dimensions;
246 
247  double spacing_x = 1;
248  double spacing_y = 1;
249  double spacing_z = 1;
250  mImage->getBaseVtkImageData()->GetSpacing(spacing_x, spacing_y, spacing_z);
251 
252  DoubleBoundingBox3D bb = getBoxWidgetSize();
253  int dim_x = (bb.begin()[1] - bb.begin()[0])/spacing_x + 1; //adding 1 because of some rounding errors, is there a better way to do this?
254  int dim_y = (bb.begin()[3] - bb.begin()[2])/spacing_y + 1;
255  int dim_z = (bb.begin()[5] - bb.begin()[4])/spacing_z + 1;
256  dimensions.push_back(dim_x);
257  dimensions.push_back(dim_y);
258  dimensions.push_back(dim_z);
259 
260  return dimensions;
261 }
262 
265 void InteractiveCropper::setBoxWidgetSize(const DoubleBoundingBox3D& bb_d)
266 {
267  if (!mImage || !mBoxWidget)
268  return;
269 
270  double bb_hard[6] =
271  { -0.5, 0.5, -0.5, 0.5, -0.5, 0.5 };
272  DoubleBoundingBox3D bb_unit(bb_hard);
273  Transform3D M = createTransformNormalize(bb_unit, bb_d);
274  Transform3D rMd = mImage->get_rMd();
275  M = rMd * M;
276 
277  vtkTransformPtr transform = vtkTransformPtr::New();
278  transform->SetMatrix(M.getVtkMatrix());
279  mBoxWidget->SetTransform(transform);
280 }
281 
284 DoubleBoundingBox3D InteractiveCropper::getBoxWidgetSize()
285 {
286  if (!mImage || !mBoxWidget)
287  {
288  return DoubleBoundingBox3D::zero();
289  }
290 
291  double bb_hard[6] =
292  { -0.5, 0.5, -0.5, 0.5, -0.5, 0.5 };
293  DoubleBoundingBox3D bb_unit(bb_hard);
294 
295  vtkTransformPtr transform = vtkTransformPtr::New();
296  mBoxWidget->GetTransform(transform);
297  Transform3D M(transform->GetMatrix());
298 
299  Transform3D rMd = mImage->get_rMd();
300  M = rMd.inv() * M;
301 
302  DoubleBoundingBox3D bb_new_r = cx::transform(M, bb_unit);
303 
304  return bb_new_r;
305 }
306 
307 void InteractiveCropper::setCroppingRegion(DoubleBoundingBox3D bb_d)
308 {
309  if (!mImage)
310  return;
311  mImage->setCroppingBox(bb_d);
312  emit changed();
313 }
314 
315 void InteractiveCropper::boxWasShown(bool val)
316 {
317  emit changed();
318 }
319 
324 {
325  if (!mImage)
326  return DoubleBoundingBox3D::zero();
327  return mImage->boundingBox();
328 }
329 
330 } // namespace cx
DoubleBoundingBox3D transform(const Transform3D &m, const DoubleBoundingBox3D &bb)
virtual void Execute(vtkObject *caller, unsigned long, void *)
static CropBoxEnableCallback * New()
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
DoubleBoundingBox3D getBoundingBox()
get BB in data space
boost::shared_ptr< class ActiveData > ActiveDataPtr
Definition: cxColorWidget.h:21
boost::shared_ptr< class View > ViewPtr
vtkSmartPointer< class vtkTransform > vtkTransformPtr
Definition: cxMathBase.h:41
void SetCropper(InteractiveCropper *cropper)
Transform3D createTransformNormalize(const DoubleBoundingBox3D &in, const DoubleBoundingBox3D &out)
InteractiveCropper * mCropper
DoubleBoundingBox3D getMaxBoundingBox()
static ActiveImageProxyPtr New(ActiveDataPtr activeData)
virtual void Execute(vtkObject *caller, unsigned long, void *)
static DoubleBoundingBox3D zero()
A volumetric data set.
Definition: cxImage.h:45
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.
void resetBoundingBox()
set bounding box back to initial size (entire volume)
void setView(ViewPtr view)
adds an interactive box widget to the view. Press &#39;I&#39; to show
InteractiveCropper(ActiveDataPtr activeData)
void SetCropper(bool val, InteractiveCropper *cropper)
void activeImageChanged(const QString &uid)
The original image changed signal from DataManager.
void setBoundingBox(const DoubleBoundingBox3D &bb_d)
set BB in reference space
static CropBoxCallback * New()
std::vector< int > getDimensions()
Namespace for all CustusX production code.