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