CustusX  16.5
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cxMehdiGPURayCastMultiVolumeRep.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 "cxConfig.h"
34 #ifdef CX_BUILD_MEHDI_VTKMULTIVOLUME
35 
37 #include "vtkOpenGLGPUMultiVolumeRayCastMapper.h"
38 #include <vtkVolumeProperty.h>
39 #include "cxView.h"
40 #include <vtkRenderer.h>
41 #include "cxVolumeProperty.h"
42 #include "cxImageMapperMonitor.h"
43 #include "cxImage.h"
44 #include <vtkImageData.h>
45 #include <vtkMatrix4x4.h>
46 #include <vtkTransform.h>
47 #include "cxGPUImageBuffer.h"
48 #include "cxReporter.h"
49 #include <vtkPlane.h>
50 #include "cxLogger.h"
51 #include "cxImageEnveloper.h"
52 #include "cxTypeConversions.h"
53 #include <vtkRenderWindow.h>
54 
55 namespace cx
56 {
57 
59 {
61  retval->init(); // contains virtual functions
62  return ImageMapperMonitorPtr(retval);
63 }
64 
66  ImageMapperMonitor(volume,image), mVolumeIndex(volumeIndex)
67 {
68 }
69 
70 vtkOpenGLGPUMultiVolumeRayCastMapperPtr MehdiGPURayCastMultiVolumeRepImageMapperMonitor::getMehdiMapper()
71 {
73  mapper = dynamic_cast<vtkOpenGLGPUMultiVolumeRayCastMapper*>(mVolume->GetMapper());
74  return mapper;
75 }
76 
78 {
79  vtkOpenGLGPUMultiVolumeRayCastMapperPtr mapper = this->getMehdiMapper();
80  if (!mapper)
81  return;
82  mapper->RemoveClippingPlane(mVolumeIndex);
83 }
84 
86 {
87  vtkOpenGLGPUMultiVolumeRayCastMapperPtr mapper = this->getMehdiMapper();
88  if (!mapper)
89  return;
90  std::vector<vtkPlanePtr> planes = mImage->getAllClipPlanes();
91  if (planes.empty())
92  {
93  mapper->RemoveClippingPlane(mVolumeIndex);
94  return;
95  }
96  else
97  {
98  mapper->AddClippingPlane(mVolumeIndex, planes[0]);
99  }
100 }
101 
103 {
104  vtkOpenGLGPUMultiVolumeRayCastMapperPtr mapper = this->getMehdiMapper();
105  if (!mapper)
106  return;
107 
108  mapper->SetCropping(mVolumeIndex, mImage->getCropping());
109 
110  DoubleBoundingBox3D bb_d = mImage->getCroppingBox();
111 
112  mapper->SetCroppingRegionPlanes(mVolumeIndex, bb_d.begin());
113  mapper->Update();
114 }
115 
116 
118 
120  mMaxVoxels(10*1000*1000)
121 {
122 }
123 
125 {
126  mMaxVoxels = maxVoxels;
127 }
128 
130 
131 
132 
133 MehdiGPURayCastMultiVolumeRep::~MehdiGPURayCastMultiVolumeRep()
134 {
135 }
136 
137 MehdiGPURayCastMultiVolumeRep::MehdiGPURayCastMultiVolumeRep() :
138  mVolume(vtkVolumePtr::New())
139 {
140 }
141 
142 void MehdiGPURayCastMultiVolumeRep::addRepActorsToViewRenderer(View* view)
143 {
144  view->getRenderer()->AddVolume(mVolume);
145 }
146 
147 void MehdiGPURayCastMultiVolumeRep::removeRepActorsFromViewRenderer(View* view)
148 {
149  view->getRenderer()->RemoveVolume(mVolume);
150 }
151 
152 void MehdiGPURayCastMultiVolumeRep::setImages(std::vector<ImagePtr> images)
153 {
154  if (images==mImages)
155  return;
156 
157  this->disconnectImages();
158  this->clearVolume();
159 
160  mImages = images;
161 
162  this->setupVolume();
163  this->connectImages();
164 }
165 
166 void MehdiGPURayCastMultiVolumeRep::clearVolume()
167 {
168  mMonitors.clear();
169  mVolumeProperties.clear();
170 
171  // should not be necessary, but seems that mapper is not cleared by vtk.
172  // http://vtk.1045678.n5.nabble.com/quot-a-vtkShader2-object-is-being-deleted-before-ReleaseGraphicsResources-has-been-called-quot-with-r-td4872396.html
173  if (this->getView())
174  mVolume->ReleaseGraphicsResources(this->getView()->getRenderWindow());
175  mVolume->SetMapper(NULL);
176 
177  mReferenceImage.reset();
178  mReferenceProperty.reset();
179  mMapper = NULL;
180 }
181 
182 void MehdiGPURayCastMultiVolumeRep::vtkImageDataChangedSlot()
183 {
184  // this call is extremly slow, as the entire rep is rebuilt (up to 5 seconds). Solution is to optimize/repalce mapper.
185  this->clearVolume();
186  this->setupVolume();
187 }
188 
189 void MehdiGPURayCastMultiVolumeRep::transformChangedSlot()
190 {
191  this->vtkImageDataChangedSlot();
192 
193  // no good: must call entire setupVolume() during init of mapper.
194 // this->setupReferenceVolumeAndPropertiesAndConnectToVolume();
195 // this->updateTransforms();
196 }
197 
198 
199 // use in setupVolume:
200 // // example code for how to allocate on gpu and return uid:
201 // GPUImageDataBufferPtr dataBuffer = GPUImageBufferRepository::getInstance()->getGPUImageDataBuffer(
202 // mImages[i]->getBaseVtkImageData());
203  // crashes: must probably initialize gl context.
204 // dataBuffer->allocate();
205 // unsigned int glUint = dataBuffer->getTextureUid();
206 
207 
208 void MehdiGPURayCastMultiVolumeRep::setupVolume()
209 {
210  if (mImages.empty())
211  return;
212 
213  this->setupVolumeProperties();
214 
215  this->initializeMapper();
216 
217  for (unsigned i=0; i<mImages.size(); ++i)
218  {
219  // index starts with main volume (and continues into additionalVolumes()), thus +1
220  mMapper->SetInput(i+1, mImages[i]->getBaseVtkImageData());
221  mMapper->SetAdditionalProperty(i, mVolumeProperties[i]->getVolumeProperty() );//Mehdi
222  }
223 
224  this->setupReferenceVolumeAndPropertiesAndConnectToVolume();
225 
226  this->updateTransforms();
227 
228  // call after mVolume has been initialized
229  this->setupMonitor();
230 
231  mMapper->Update();
232 }
233 
234 void MehdiGPURayCastMultiVolumeRep::initializeMapper()
235 {
236  mMapper = vtkOpenGLGPUMultiVolumeRayCastMapperPtr::New();
237  mMapper->setNumberOfAdditionalVolumes(mImages.size());
238  mVolume->SetMapper(mMapper);
239 }
240 
241 
242 void MehdiGPURayCastMultiVolumeRep::setupReferenceVolumeAndPropertiesAndConnectToVolume()
243 {
244  SSC_ASSERT(!mImages.empty());
245 
246  mReferenceImage = this->getEnvelopingImage();
247  mReferenceProperty = VolumeProperty::create();
248  // hack: use properties from first input image.
249  // This is because some properties (at least shading) is taken from here.
250  mReferenceProperty->setImage(mImages[0]);
251  mVolume->SetProperty( mReferenceProperty->getVolumeProperty() );
252  mMapper->SetInput(0, mReferenceImage->getBaseVtkImageData());
253 }
254 
255 void MehdiGPURayCastMultiVolumeRep::updateTransforms()
256 {
257  if (mImages.empty())
258  return;
259 
260  SSC_ASSERT(mReferenceImage);
261 
262  Transform3D rMd0 = mReferenceImage->get_rMd(); // use on first volume
263  mVolume->SetUserMatrix(rMd0.getVtkMatrix());
264 
265  for (unsigned i=0; i<mImages.size(); ++i)
266  {
267  Transform3D rMdi = mImages[i]->get_rMd();
268  Transform3D d0Mdi = rMd0.inv() * rMdi; // use on additional volumes
269 
270  mMapper->SetAdditionalInputUserTransform(i, d0Mdi.getVtkTransform());
271  }
272 }
273 
274 ImagePtr MehdiGPURayCastMultiVolumeRep::getEnvelopingImage()
275 {
276  ImageEnveloperPtr generator;
277  generator = ImageEnveloper::create();
278  generator->setImages(mImages);
279  generator->setMaxEnvelopeVoxels(mMaxVoxels);
280  return generator->getEnvelopingImage();
281 }
282 
283 void MehdiGPURayCastMultiVolumeRep::disconnectImages()
284 {
285  for (unsigned i=0; i<mImages.size(); ++i)
286  {
287  disconnect(mImages[i].get(), SIGNAL(vtkImageDataChanged()), this, SLOT(vtkImageDataChangedSlot()));
288  disconnect(mImages[i].get(), SIGNAL(transformChanged()), this, SLOT(transformChangedSlot()));
289  }
290 }
291 
292 void MehdiGPURayCastMultiVolumeRep::connectImages()
293 {
294  for (unsigned i=0; i<mImages.size(); ++i)
295  {
296  connect(mImages[i].get(), SIGNAL(vtkImageDataChanged()), this, SLOT(vtkImageDataChangedSlot()));
297  connect(mImages[i].get(), SIGNAL(transformChanged()), this, SLOT(transformChangedSlot()));
298  }
299 }
300 
301 void MehdiGPURayCastMultiVolumeRep::setupMonitor()
302 {
303  mMonitors.resize(mImages.size());
304  for (unsigned i=0; i<mImages.size(); ++i)
305  {
306  mMonitors[i] = MehdiGPURayCastMultiVolumeRepImageMapperMonitor::create(mVolume, mImages[i], i+1);
307  }
308 }
309 
310 void MehdiGPURayCastMultiVolumeRep::setupVolumeProperties()
311 {
312  mVolumeProperties.clear();
313  for (unsigned i=0; i<mImages.size(); ++i)
314  {
316  property->setImage(mImages[i]);
317  mVolumeProperties.push_back(property);
318  }
319 }
320 
321 } // namespace cx
322 
323 #endif //CX_BUILD_MEHDI_VTKMULTIVOLUME
vtkSmartPointer< class vtkVolume > vtkVolumePtr
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
vtkSmartPointer< class vtkOpenGLGPUMultiVolumeRayCastMapper > vtkOpenGLGPUMultiVolumeRayCastMapperPtr
static ImageMapperMonitorPtr create(vtkVolumePtr volume, ImagePtr image, int volumeIndex)
boost::shared_ptr< class Image > ImagePtr
Definition: cxDicomWidget.h:48
static ImageEnveloperPtr create()
boost::shared_ptr< class ImageMapperMonitor > ImageMapperMonitorPtr
static VolumePropertyPtr create()
boost::shared_ptr< class VolumeProperty > VolumePropertyPtr
long mMaxVoxels
always resample volume below this size.
MehdiGPURayCastMultiVolumeRepImageMapperMonitor(vtkVolumePtr volume, ImagePtr image, int volumeIndex)
virtual void setMaxVolumeSize(long maxVoxels)
boost::shared_ptr< class ImageEnveloper > ImageEnveloperPtr