7 #include "visuVTKVRAdaptor/SVolume.hpp" 9 #include <fwCom/Slot.hxx> 10 #include <fwCom/Slots.hxx> 12 #include <fwData/TransferFunction.hpp> 14 #include <fwDataTools/fieldHelper/MedicalImageHelpers.hpp> 16 #include <fwServices/macros.hpp> 18 #include <fwVtkIO/vtk.hpp> 20 #include <vtkBoundingBox.h> 21 #include <vtkBoxRepresentation.h> 22 #include <vtkBoxWidget2.h> 23 #include <vtkColorTransferFunction.h> 24 #include <vtkCommand.h> 25 #include <vtkImageImport.h> 26 #include <vtkImageResample.h> 27 #include <vtkPiecewiseFunction.h> 28 #include <vtkPlaneCollection.h> 29 #include <vtkRenderer.h> 30 #include <vtkRenderWindow.h> 31 #include <vtkRenderWindowInteractor.h> 32 #include <vtkSmartVolumeMapper.h> 33 #include <vtkTransform.h> 34 #include <vtkVolume.h> 35 #include <vtkVolumeProperty.h> 53 cb->m_adaptor = adaptor;
59 virtual void Execute( ::vtkObject* caller,
unsigned long,
void* )
84 virtual void Execute( vtkObject* caller,
unsigned long eventId,
void*)
86 vtkRenderWindow* win = vtkRenderWindow::SafeDownCast(caller);
89 if( win->GetEventPending() )
91 win->SetAbortRender(1);
108 callback->m_adaptor = adaptor;
114 virtual void Execute( vtkObject* caller,
unsigned long eventId,
void*)
117 m_adaptor->updateTransform();
124 static const ::fwCom::Slots::SlotKeyType s_RESET_BOX_WIDGET_SLOT =
"resetBoxWidget";
125 static const ::fwCom::Slots::SlotKeyType s_ACTIVATE_BOX_CLIPPING_SLOT =
"activateBoxClipping";
126 static const ::fwCom::Slots::SlotKeyType s_SHOW_SLOT =
"show";
128 const ::fwServices::IService::KeyType SVolume::s_IMAGE_INOUT =
"image";
129 const ::fwServices::IService::KeyType SVolume::s_TF_INOUT =
"tf";
133 SVolume::SVolume() noexcept :
136 m_clippingPlanes(
nullptr),
137 m_volumeMapper( vtkSmartVolumeMapper::New()),
138 m_volumeProperty(vtkVolumeProperty::New()),
139 m_volume(vtkVolume::New()),
140 m_opacityTransferFunction(vtkPiecewiseFunction::New()),
141 m_colorTransferFunction(vtkColorTransferFunction::New()),
142 m_abortCommand(AbortCallback::New()),
143 m_boxWidget(vtkBoxWidget2::New()),
144 m_croppingCommand(
nullptr),
145 m_transformCommand(
nullptr),
146 m_croppingBoxDefaultState(
true),
147 m_cropBoxTransform(
nullptr),
148 m_autoResetCamera(
true),
149 m_reductionFactor(1.0),
150 m_blendMode(
"composite")
152 m_boxWidget->KeyPressActivationOff();
153 m_boxWidget->SetRotationEnabled(0);
154 vtkBoxRepresentation* repr = vtkBoxRepresentation::New();
155 m_boxWidget->SetRepresentation(repr);
162 this->installTFSlots(
this);
167 SVolume::~SVolume() noexcept
169 m_volumeMapper->Delete();
170 m_volumeMapper =
nullptr;
175 m_abortCommand->Delete();
176 m_abortCommand =
nullptr;
178 if (m_clippingPlanes)
180 m_clippingPlanes->Delete();
181 m_clippingPlanes =
nullptr;
184 m_boxWidget->Delete();
185 m_boxWidget =
nullptr;
187 m_opacityTransferFunction->Delete();
188 m_opacityTransferFunction =
nullptr;
190 m_colorTransferFunction->Delete();
191 m_colorTransferFunction =
nullptr;
196 void SVolume::setClippingPlanesId(::fwRenderVTK::SRender::VtkObjectIdType
id)
198 m_clippingPlanesId = id;
203 void SVolume::setVtkClippingPlanes(vtkPlaneCollection* planes)
205 m_clippingPlanes = planes;
212 this->configureParams();
214 const ConfigType config = this->getConfigTree().get_child(
"config.<xmlattr>");
216 this->setClippingPlanesId( config.get<std::string>(
"clippingplanes",
"") );
218 m_autoResetCamera = config.get<std::string>(
"autoresetcamera",
"yes") ==
"yes";
221 m_croppingBoxDefaultState = config.get<std::string>(
"croppingBox",
"yes") ==
"yes";
224 m_cropBoxTransformID = config.get<std::string>(
"cropBoxTransform",
"");
226 m_reductionFactor = config.get<
double>(
"reductionFactor", 1.);
229 m_blendMode = config.get<std::string>(
"blend",
"composite");
239 ::fwData::TransferFunction::sptr tf = this->getInOut< ::fwData::TransferFunction >(s_TF_INOUT);
240 ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
243 this->setOrCreateTF(tf, image);
245 this->addToRenderer(m_volume);
247 this->getInteractor()->GetRenderWindow()->AddObserver(
"AbortCheckEvent", m_abortCommand);
250 this->activateBoxClipping( m_croppingBoxDefaultState );
252 if(!m_cropBoxTransformID.empty())
254 m_cropBoxTransform = vtkTransform::SafeDownCast( m_renderService.lock()->getVtkObject(m_cropBoxTransformID));
257 if(m_cropBoxTransform)
259 m_transformCommand = TransformCallback::New(
this);
260 m_cropBoxTransform->AddObserver( ::vtkCommand::ModifiedEvent, m_transformCommand );
262 vtkBoxRepresentation* repr = vtkBoxRepresentation::SafeDownCast( m_boxWidget->GetRepresentation() );
263 repr->SetTransform(m_cropBoxTransform);
268 m_croppingCommand = CroppingCallback::New(
this);
269 m_boxWidget->AddObserver(vtkCommand::InteractionEvent, m_croppingCommand);
271 if (!this->getTransformId().empty())
273 m_volume->SetUserTransform(this->getTransform());
281 this->removeTFConnections();
282 this->removeAllPropFromRenderer();
283 this->getInteractor()->GetRenderWindow()->RemoveObserver(m_abortCommand);
284 m_boxWidget->RemoveObserver(m_croppingCommand);
286 m_croppingCommand->Delete();
287 m_croppingCommand =
nullptr;
289 if(m_cropBoxTransform)
291 m_cropBoxTransform->RemoveObserver( m_transformCommand );
292 m_transformCommand->Delete();
293 m_transformCommand =
nullptr;
301 ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
306 this->buildPipeline();
307 this->updateImage(image);
308 this->updateVolumeTransferFunction(image);
309 this->requestRender();
317 if (key == s_TF_INOUT)
319 ::fwData::TransferFunction::sptr tf = this->getInOut< ::fwData::TransferFunction >(s_TF_INOUT);
320 ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
323 this->setOrCreateTF(tf, image);
332 ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
333 this->updateVolumeTransferFunction(image);
334 this->requestRender();
341 ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
342 this->updateVolumeTransferFunction(image);
343 this->requestRender();
348 void SVolume::updateImage( ::fwData::Image::sptr image )
350 this->updateImageInfos(image);
352 vtkImageImport* imageImport = vtkImageImport::New();
353 ::fwVtkIO::configureVTKImageImport( imageImport, image );
355 m_volumeMapper->RemoveAllClippingPlanes();
356 if (m_clippingPlanes)
358 m_volumeMapper->SetClippingPlanes(m_clippingPlanes);
361 if ( m_reductionFactor < 1.0 )
363 vtkImageResample* resample = vtkImageResample::New();
364 resample->SetInputConnection( imageImport->GetOutputPort() );
365 resample->SetAxisMagnificationFactor(0, m_reductionFactor);
366 resample->SetAxisMagnificationFactor(1, m_reductionFactor);
367 resample->SetAxisMagnificationFactor(2, m_reductionFactor);
368 m_volumeMapper->SetInputConnection(resample->GetOutputPort());
373 m_volumeMapper->SetInputConnection(imageImport->GetOutputPort());
376 m_boxWidget->GetRepresentation()->SetPlaceFactor(1.0);
377 m_boxWidget->GetRepresentation()->PlaceWidget(m_volumeMapper->GetBounds());
378 m_boxWidget->SetInteractor(this->getInteractor());
380 vtkVolumeMapper::SafeDownCast(m_volumeMapper)->CroppingOn();
381 vtkVolumeMapper::SafeDownCast(m_volumeMapper)->SetCroppingRegionPlanes( m_volumeMapper->GetBounds() );
383 imageImport->Delete();
385 if (m_autoResetCamera)
387 this->getRenderer()->ResetCamera();
390 this->setVtkPipelineModified();
395 void SVolume::updateVolumeTransferFunction( ::fwData::Image::sptr image )
397 ::fwData::TransferFunction::sptr pTF = this->getTransferFunction();
398 SLM_ASSERT(
"TransferFunction null pointer", pTF);
400 m_colorTransferFunction->RemoveAllPoints();
401 m_opacityTransferFunction->RemoveAllPoints();
403 ::fwData::TransferFunction::TFValueVectorType values = pTF->getScaledValues();
404 ::fwData::TransferFunction::TFValueVectorType::iterator valueIter = values.begin();
405 if(pTF->getInterpolationMode() == ::fwData::TransferFunction::NEAREST)
407 m_colorTransferFunction->AllowDuplicateScalarsOn();
408 m_opacityTransferFunction->AllowDuplicateScalarsOn();
410 for(const ::fwData::TransferFunction::TFDataType::value_type& tfPoint : pTF->getTFData())
412 const ::fwData::TransferFunction::TFValueType& value = *valueIter;
413 ::fwData::TransferFunction::TFValueType valuePrevious = *valueIter;
414 ::fwData::TransferFunction::TFValueType valueNext = *valueIter;
415 if(valueIter != values.begin())
417 valuePrevious = *(valueIter - 1);
419 if(valueIter != (values.end()-1))
421 valueNext = *(valueIter + 1);
424 const ::fwData::TransferFunction::TFColor& color = tfPoint.second;
426 m_colorTransferFunction->AddRGBPoint(valuePrevious + (value - valuePrevious) / 2., color.r, color.g,
428 m_colorTransferFunction->AddRGBPoint(value + (valueNext - value) / 2., color.r, color.g, color.b );
430 m_opacityTransferFunction->AddPoint(valuePrevious + (value -valuePrevious) / 2., color.a );
431 m_opacityTransferFunction->AddPoint(value + (valueNext - value) / 2., color.a );
438 for(const ::fwData::TransferFunction::TFDataType::value_type& tfPoint : pTF->getTFData())
440 const ::fwData::TransferFunction::TFValueType& value = *(valueIter++);
441 const ::fwData::TransferFunction::TFColor& color = tfPoint.second;
443 m_colorTransferFunction->AddRGBPoint( value, color.r, color.g, color.b );
444 m_opacityTransferFunction->AddPoint( value, color.a );
448 m_colorTransferFunction->SetClamping(!pTF->getIsClamped());
449 m_opacityTransferFunction->SetClamping(!pTF->getIsClamped());
451 if(m_blendMode ==
"average")
454 std::pair< double, double > averageRange = this->getTransferFunction()->getWLMinMax();
455 m_volumeMapper->SetAverageIPScalarRange(averageRange.first, averageRange.second);
458 this->setVtkPipelineModified();
464 void SVolume::buildPipeline( )
466 if (!m_clippingPlanesId.empty())
468 vtkObject* o = this->getVtkObject(m_clippingPlanesId);
469 vtkPlaneCollection* planes = vtkPlaneCollection::SafeDownCast(o);
470 this->setVtkClippingPlanes( planes );
473 m_volumeProperty->SetScalarOpacity(m_opacityTransferFunction);
474 m_volumeProperty->SetColor(m_colorTransferFunction);
476 m_volumeProperty->ShadeOn();
477 m_volumeProperty->SetInterpolationTypeToLinear();
479 m_volumeProperty->SetAmbient( 0.2 );
480 m_volumeProperty->SetDiffuse( 1.0 );
481 m_volumeProperty->SetSpecular( 1.0 );
482 m_volumeProperty->SetSpecularPower( 10.0 );
485 if(m_blendMode ==
"min")
487 m_volumeMapper->SetBlendModeToMinimumIntensity();
489 else if(m_blendMode ==
"max")
491 m_volumeMapper->SetBlendModeToMaximumIntensity();
493 else if(m_blendMode ==
"average")
495 m_volumeMapper->SetRequestedRenderMode(vtkSmartVolumeMapper::GPURenderMode);
496 m_volumeMapper->SetBlendModeToAverageIntensity();
498 else if(m_blendMode ==
"additive")
500 m_volumeMapper->SetBlendModeToAdditive();
503 else if(m_blendMode ==
"composite")
505 m_volumeMapper->SetBlendModeToComposite();
509 OSLM_WARN(
"blend mode '"<< m_blendMode <<
"' is unknown. Should be min, max, average, composite or additive.");
512 m_volume->SetMapper(m_volumeMapper);
513 m_volume->SetProperty(m_volumeProperty);
515 this->setVtkPipelineModified();
522 m_boxWidget->GetRepresentation()->SetPlaceFactor(1.0);
523 m_boxWidget->GetRepresentation()->PlaceWidget( m_volumeMapper->GetBounds() );
524 vtkVolumeMapper::SafeDownCast( m_volumeMapper )->SetCroppingRegionPlanes( m_volumeMapper->GetBounds() );
525 if (m_autoResetCamera)
527 this->getRenderer()->ResetCamera();
529 this->setVtkPipelineModified();
530 this->requestRender();
545 this->setVtkPipelineModified();
546 this->requestRender();
564 vtkVolumeMapper* mapper = vtkVolumeMapper::SafeDownCast(m_volumeMapper);
565 double* croppingRegionPlanes = m_boxWidget->GetRepresentation()->GetBounds();
567 vtkBoundingBox boundingBoxCrop(croppingRegionPlanes);
568 vtkBoundingBox boundingBoxVolume(mapper->GetBounds());
570 if(boundingBoxCrop.Intersects(boundingBoxVolume))
572 mapper->SetCroppingRegionPlanes( croppingRegionPlanes );
576 mapper->SetCroppingRegionPlanes(0., 0., 0., 0., 0., 0.);
584 if(m_cropBoxTransform)
586 vtkBoxRepresentation* repr = vtkBoxRepresentation::SafeDownCast( m_boxWidget->GetRepresentation() );
589 m_cropBoxTransform->RemoveObserver(m_transformCommand);
590 repr->GetTransform(m_cropBoxTransform);
591 m_cropBoxTransform->Modified();
592 m_cropBoxTransform->AddObserver(vtkCommand::ModifiedEvent, m_transformCommand);
601 if(m_cropBoxTransform)
603 vtkBoxRepresentation* repr = vtkBoxRepresentation::SafeDownCast( m_boxWidget->GetRepresentation() );
606 m_boxWidget->RemoveObserver(m_croppingCommand);
607 repr->SetTransform(m_cropBoxTransform);
608 m_boxWidget->AddObserver(vtkCommand::InteractionEvent, m_croppingCommand);
617 m_volume->SetVisibility(isVisible);
618 this->setVtkPipelineModified();
619 this->requestRender();
VISUVTKVRADAPTOR_API void starting() override
Initialize the service activity.
VISUVTKVRADAPTOR_API void updateTransform()
Update associated transform adaptor with CropBox transform.
This class is a helper to define the connections of a service and its data.
virtual VISUVTKVRADAPTOR_API void updateTFPoints() override
Slot: updates the volume transfer function.
Volume rendering adaptors.
VISUVTKVRADAPTOR_API void crop()
Apply the cropping on volume rendering.
This adaptor displays a volume image.
virtual void swapping()
Swap the service from associated object to another object.
virtual VISUVTKVRADAPTOR_API void updateTFWindowing(double window, double level) override
Slot: updates the volume transfer function.
void resetBoxWidget()
Slot: reset the clipping box widget around the volume.
void activateBoxClipping(bool activate)
Slot: show/hide clipping box.
#define OSLM_WARN(message)
#define SLM_ASSERT(message, cond)
work like 'assert' from 'cassert', with in addition a message logged by spylog (with FATAL loglevel) ...
virtual VISUVTKVRADAPTOR_API KeyConnectionsMap getAutoConnections() const override
Returns proposals to connect service slots to associated object signals, this method is used for obj/...
VISUVTKVRADAPTOR_API void stopping() override
Uninitialize the service activity. The stop() method is always invoked before destroying a service...
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_BUFFER_MODIFIED_SIG
Type of signal when image's buffer is added.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_MODIFIED_SIG
Key in m_signals map of signal m_sigModified.
VISUVTKVRADAPTOR_API void updateCropBoxTransform()
Update CropBox transform with transform adaptor.
VISUVTKVRADAPTOR_API void updating() override
Perform some computations according to object (this service is attached to) attribute values and its ...
void show(bool isVisible)
Slot: show/hide the volume.
VISUVTKVRADAPTOR_API void configuring() override
Configure the service before starting. Apply the configuration to service.
Base class for VTK adaptors.