CustusX  15.8
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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) 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  * cxInteractiveCropper.cpp
35  *
36  * \date Aug 24, 2010
37  * \author christiana
38  */
39 #include "cxInteractiveCropper.h"
40 
41 #include "cxView.h"
42 
43 #include <vector>
44 #include <vtkTransform.h>
45 #include <vtkAbstractVolumeMapper.h>
46 #include <vtkVolumeMapper.h>
47 #include <vtkRenderWindow.h>
48 #include <vtkRenderer.h>
49 #include <vtkImageData.h>
50 #include <vtkCommand.h>
51 #include <vtkBoxWidget2.h>
52 #include <vtkBoxWidget.h>
53 #include "cxTypeConversions.h"
54 #include "cxBoundingBox3D.h"
55 #include "cxImage.h"
56 #include "cxTransform3D.h"
57 #include "cxVolumetricRep.h"
58 #include "cxCoreServices.h"
59 #include "cxPatientModelService.h"
60 
61 #include "cxActiveImageProxy.h"
62 #include "cxPatientModelService.h"
63 
64 namespace cx
65 {
66 
67 class CropBoxCallback: public vtkCommand
68 {
69 public:
71  {
72  }
73  static CropBoxCallback* New()
74  {
75  return new CropBoxCallback;
76  }
78  {
79  mCropper = cropper;
80  }
81  virtual void Execute(vtkObject* caller, unsigned long, void*)
82  {
83  DoubleBoundingBox3D bb_new = mCropper->getBoxWidgetSize();
84  mCropper->setCroppingRegion(bb_new);
85  }
87 };
88 
89 class CropBoxEnableCallback: public vtkCommand
90 {
91 public:
93  {
94  }
96  {
97  return new CropBoxEnableCallback;
98  }
99  void SetCropper(bool val, InteractiveCropper* cropper)
100  {
101  mValue = val;
102  mCropper = cropper;
103  }
104  virtual void Execute(vtkObject* caller, unsigned long, void*)
105  {
106  DoubleBoundingBox3D bb_new = mCropper->getBoxWidgetSize();
107  mCropper->boxWasShown(mValue);
108  }
109  bool mValue;
111 };
112 
113 //---------------------------------------------------------
114 //---------------------------------------------------------
115 //---------------------------------------------------------
116 
117 
118 InteractiveCropper::InteractiveCropper(CoreServicesPtr backend/*PatientModelServicePtr patientModelService*/) :
119  mBackend(backend)
120 // mPatientModelService(patientModelService)
121 {
122  mActiveImageProxy = ActiveImageProxy::New(mBackend->patientModelService);
123  connect(mActiveImageProxy.get(), &ActiveImageProxy::activeImageChanged, this, &InteractiveCropper::imageChangedSlot);
124  connect(mActiveImageProxy.get(), SIGNAL(cropBoxChanged()), this, SLOT(imageCropChangedSlot()));
125 }
126 
127 void InteractiveCropper::initialize()
128 {
129  if (mBoxWidget) // already initialized
130  return;
131 
132  mBoxWidget = vtkBoxWidgetPtr::New();
133  mBoxWidget->RotationEnabledOff();
134 
135  double bb_hard[6] =
136  { -1, 1, -1, 1, -1, 1 };
137  mBoxWidget->PlaceWidget(bb_hard);
138 
139  mCropBoxCallback = CropBoxCallbackPtr::New();
140  mCropBoxCallback->SetCropper(this);
141  mCropBoxEnableCallback = CropBoxEnableCallbackPtr::New();
142  mCropBoxEnableCallback->SetCropper(true, this);
143  mCropBoxDisableCallback = CropBoxEnableCallbackPtr::New();
144  mCropBoxDisableCallback->SetCropper(false, this);
145 
146  mBoxWidget->SetInteractor(mView->getRenderWindow()->GetInteractor());
147 
148  mBoxWidget->SetEnabled(false);
149 }
150 
152 {
153  mView = view;
154  this->updateBoxWidgetInteractor();
155 }
156 
157 void InteractiveCropper::updateBoxWidgetInteractor()
158 {
159  if (!mView)
160  return;
161 
162  this->initialize();
163 
164  if (this->getUseCropping())
165  {
166  mBoxWidget->SetInteractor(mView->getRenderWindow()->GetInteractor());
167  mBoxWidget->AddObserver(vtkCommand::InteractionEvent, mCropBoxCallback);
168  mBoxWidget->AddObserver(vtkCommand::EnableEvent, mCropBoxEnableCallback);
169  mBoxWidget->AddObserver(vtkCommand::DisableEvent, mCropBoxDisableCallback);
170  }
171  else
172  {
173  mBoxWidget->RemoveObserver(vtkCommand::InteractionEvent);
174  mBoxWidget->RemoveObserver(vtkCommand::EnableEvent);
175  mBoxWidget->RemoveObserver(vtkCommand::DisableEvent);
176  }
177 }
178 
180 {
181  if (!mImage)
182  return;
183  if (!mBoxWidget)
184  return;
185  if (this->getShowBoxWidget() == on)
186  return;
187 
188  //Turn on cropping if not on to save user from pressing two boxes
189  if (!mImage->getCropping() && on)
190  this->useCropping(true);
191 
192  mBoxWidget->SetEnabled(on);
193  emit changed();
194 }
195 
199 {
200  if (!mImage || !mBoxWidget)
201  return DoubleBoundingBox3D(0,0,0,0,0,0);
202  return mImage->getCroppingBox();
203 }
204 
206 {
207  this->setCroppingRegion(bb_d);
208  this->setBoxWidgetSize(bb_d);
209 }
210 
212 {
213  if (this->getUseCropping() == on)
214  return;
215 
216  if (!mImage)
217  return;
218 
219  mImage->setCropping(on);
220 }
221 
222 void InteractiveCropper::imageCropChangedSlot()
223 {
224  if (!mImage)
225  return;
226 
227  DoubleBoundingBox3D bb_d = this->getBoundingBox();
228  this->setBoxWidgetSize(bb_d);
229  this->updateBoxWidgetInteractor();
230 
231  if (!mImage->getCropping())
232  this->showBoxWidget(false);
233 
234  emit changed();
235 }
236 
238 {
239  emit changed();
240 }
241 
242 void InteractiveCropper::imageChangedSlot()
243 {
244 // mImage = mPatientModelService->getActiveImage();
245  mImage = mBackend->patientModelService->getActiveImage();
246 
247  this->imageCropChangedSlot();
248  emit changed();
249 }
250 
252 {
253  if (!mImage)
254  return false;
255  return mImage->getCropping();
256 }
257 
259 {
260  if (!mBoxWidget)
261  return false;
262  return mBoxWidget->GetEnabled();
263 }
264 
266 {
267  std::vector<int> dimensions;
268  if(!mImage)
269  return dimensions;
270 
271  double spacing_x = 1;
272  double spacing_y = 1;
273  double spacing_z = 1;
274  mImage->getBaseVtkImageData()->GetSpacing(spacing_x, spacing_y, spacing_z);
275 
276  DoubleBoundingBox3D bb = getBoxWidgetSize();
277  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?
278  int dim_y = (bb.begin()[3] - bb.begin()[2])/spacing_y + 1;
279  int dim_z = (bb.begin()[5] - bb.begin()[4])/spacing_z + 1;
280  dimensions.push_back(dim_x);
281  dimensions.push_back(dim_y);
282  dimensions.push_back(dim_z);
283 
284  return dimensions;
285 }
286 
289 void InteractiveCropper::setBoxWidgetSize(const DoubleBoundingBox3D& bb_d)
290 {
291  if (!mImage || !mBoxWidget)
292  return;
293 
294  double bb_hard[6] =
295  { -0.5, 0.5, -0.5, 0.5, -0.5, 0.5 };
296  DoubleBoundingBox3D bb_unit(bb_hard);
297  Transform3D M = createTransformNormalize(bb_unit, bb_d);
298  Transform3D rMd = mImage->get_rMd();
299  M = rMd * M;
300 
301  vtkTransformPtr transform = vtkTransformPtr::New();
302  transform->SetMatrix(M.getVtkMatrix());
303  mBoxWidget->SetTransform(transform);
304 }
305 
308 DoubleBoundingBox3D InteractiveCropper::getBoxWidgetSize()
309 {
310  if (!mImage || !mBoxWidget)
311  {
312  return DoubleBoundingBox3D::zero();
313  }
314 
315  double bb_hard[6] =
316  { -0.5, 0.5, -0.5, 0.5, -0.5, 0.5 };
317  DoubleBoundingBox3D bb_unit(bb_hard);
318 
319  vtkTransformPtr transform = vtkTransformPtr::New();
320  mBoxWidget->GetTransform(transform);
321  Transform3D M(transform->GetMatrix());
322 
323  Transform3D rMd = mImage->get_rMd();
324  M = rMd.inv() * M;
325 
326  DoubleBoundingBox3D bb_new_r = cx::transform(M, bb_unit);
327 
328  return bb_new_r;
329 }
330 
331 void InteractiveCropper::setCroppingRegion(DoubleBoundingBox3D bb_d)
332 {
333  if (!mImage)
334  return;
335  mImage->setCroppingBox(bb_d);
336  emit changed();
337 }
338 
339 void InteractiveCropper::boxWasShown(bool val)
340 {
341  emit changed();
342 }
343 
348 {
349  if (!mImage)
350  return DoubleBoundingBox3D::zero();
351  return mImage->boundingBox();
352 }
353 
354 } // 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
InteractiveCropper(CoreServicesPtr backend)
boost::shared_ptr< class View > ViewPtr
vtkSmartPointer< class vtkTransform > vtkTransformPtr
Definition: cxMathBase.h:62
void SetCropper(InteractiveCropper *cropper)
Transform3D createTransformNormalize(const DoubleBoundingBox3D &in, const DoubleBoundingBox3D &out)
InteractiveCropper * mCropper
DoubleBoundingBox3D getMaxBoundingBox()
virtual void Execute(vtkObject *caller, unsigned long, void *)
static DoubleBoundingBox3D zero()
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 'I' to show
boost::shared_ptr< class CoreServices > CoreServicesPtr
Definition: cxCameraStyle.h:59
static ActiveImageProxyPtr New(PatientModelServicePtr patientModelService)
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()