diff --git a/Modules/US/USModel/mitkUSDevice.cpp b/Modules/US/USModel/mitkUSDevice.cpp index bfdd6783c3..35305f7636 100644 --- a/Modules/US/USModel/mitkUSDevice.cpp +++ b/Modules/US/USModel/mitkUSDevice.cpp @@ -1,671 +1,672 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkUSDevice.h" #include "mitkImageReadAccessor.h" // US Control Interfaces #include "mitkUSControlInterfaceProbes.h" #include "mitkUSControlInterfaceBMode.h" #include "mitkUSControlInterfaceDoppler.h" // Microservices #include #include #include #include mitk::USDevice::PropertyKeys mitk::USDevice::GetPropertyKeys() { static mitk::USDevice::PropertyKeys propertyKeys; return propertyKeys; } mitk::USDevice::USImageCropArea mitk::USDevice::GetCropArea() { MITK_INFO << "Return Crop Area L:" << m_CropArea.cropLeft << " R:" << m_CropArea.cropRight << " T:" << m_CropArea.cropTop << " B:" << m_CropArea.cropBottom; return m_CropArea; } mitk::USDevice::USDevice(std::string manufacturer, std::string model) : mitk::ImageSource(), m_IsFreezed(false), m_DeviceState(State_NoState), m_Manufacturer(manufacturer), m_Name(model), m_SpawnAcquireThread(true), m_MultiThreader(itk::MultiThreader::New()), m_ImageMutex(itk::FastMutexLock::New()), m_ThreadID(-1), m_UnregisteringStarted(false) { USImageCropArea empty; empty.cropBottom = 0; empty.cropTop = 0; empty.cropLeft = 0; empty.cropRight = 0; this->m_CropArea = empty; // set number of outputs this->SetNumberOfIndexedOutputs(1); // create a new output mitk::Image::Pointer newOutput = mitk::Image::New(); this->SetNthOutput(0, newOutput); } mitk::USDevice::USDevice(mitk::USImageMetadata::Pointer metadata) : mitk::ImageSource(), m_IsFreezed(false), m_DeviceState(State_NoState), m_SpawnAcquireThread(true), m_MultiThreader(itk::MultiThreader::New()), m_ImageMutex(itk::FastMutexLock::New()), m_ThreadID(-1), m_UnregisteringStarted(false) { m_Manufacturer = metadata->GetDeviceManufacturer(); m_Name = metadata->GetDeviceModel(); m_Comment = metadata->GetDeviceComment(); USImageCropArea empty; empty.cropBottom = 0; empty.cropTop = 0; empty.cropLeft = 0; empty.cropRight = 0; this->m_CropArea = empty; // set number of outputs this->SetNumberOfIndexedOutputs(1); // create a new output mitk::Image::Pointer newOutput = mitk::Image::New(); this->SetNthOutput(0, newOutput); } mitk::USDevice::~USDevice() { if (m_ThreadID >= 0) { m_MultiThreader->TerminateThread(m_ThreadID); } // make sure that the us device is not registered at the micro service // anymore after it is destructed this->UnregisterOnService(); } mitk::USAbstractControlInterface::Pointer mitk::USDevice::GetControlInterfaceCustom() { MITK_INFO << "Custom control interface does not exist for this object."; return 0; } mitk::USControlInterfaceBMode::Pointer mitk::USDevice::GetControlInterfaceBMode() { MITK_INFO << "Control interface BMode does not exist for this object."; return 0; } mitk::USControlInterfaceProbes::Pointer mitk::USDevice::GetControlInterfaceProbes() { MITK_INFO << "Control interface Probes does not exist for this object."; return 0; } mitk::USControlInterfaceDoppler::Pointer mitk::USDevice::GetControlInterfaceDoppler() { MITK_INFO << "Control interface Doppler does not exist for this object."; return 0; } void mitk::USDevice::SetManufacturer(std::string manufacturer) { m_Manufacturer = manufacturer; if (m_DeviceState >= State_Initialized) { this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_MANUFACTURER, manufacturer); } } void mitk::USDevice::SetName(std::string name) { m_Name = name; if (m_DeviceState >= State_Initialized) { this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_NAME, name); } } void mitk::USDevice::SetComment(std::string comment) { m_Comment = comment; if (m_DeviceState >= State_Initialized) { this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_COMMENT, comment); } } us::ServiceProperties mitk::USDevice::ConstructServiceProperties() { mitk::USDevice::PropertyKeys propertyKeys = mitk::USDevice::GetPropertyKeys(); us::ServiceProperties props; props[propertyKeys.US_PROPKEY_ISCONNECTED] = this->GetIsConnected() ? "true" : "false"; props[propertyKeys.US_PROPKEY_ISACTIVE] = this->GetIsActive() ? "true" : "false"; props[propertyKeys.US_PROPKEY_LABEL] = this->GetServicePropertyLabel(); // get identifier of selected probe if there is one selected mitk::USControlInterfaceProbes::Pointer probesControls = this->GetControlInterfaceProbes(); if (probesControls.IsNotNull() && probesControls->GetIsActive()) { mitk::USProbe::Pointer probe = probesControls->GetSelectedProbe(); if (probe.IsNotNull()) { props[propertyKeys.US_PROPKEY_PROBES_SELECTED] = probe->GetName(); } } props[propertyKeys.US_PROPKEY_CLASS] = GetDeviceClass(); props[propertyKeys.US_PROPKEY_MANUFACTURER] = m_Manufacturer; props[propertyKeys.US_PROPKEY_NAME] = m_Name; props[propertyKeys.US_PROPKEY_COMMENT] = m_Comment; m_ServiceProperties = props; return props; } void mitk::USDevice::UnregisterOnService() { // unregister on micro service if (m_ServiceRegistration && !m_UnregisteringStarted) { // make sure that unregister is not started a second // time due to a callback during unregister for example m_UnregisteringStarted = true; m_ServiceRegistration.Unregister(); m_ServiceRegistration = 0; } } bool mitk::USDevice::Initialize() { if (!this->OnInitialization()) { return false; } m_DeviceState = State_Initialized; // Get Context and Module us::ModuleContext* context = us::GetModuleContext(); us::ServiceProperties props = this->ConstructServiceProperties(); m_ServiceRegistration = context->RegisterService(this, props); return true; } bool mitk::USDevice::Connect() { MITK_DEBUG << "mitk::USDevice::Connect() called"; if (this->GetIsConnected()) { MITK_INFO("mitkUSDevice") << "Tried to connect an ultrasound device that " "was already connected. Ignoring call..."; return true; } if (!this->GetIsInitialized()) { MITK_ERROR("mitkUSDevice") << "Cannot connect device if it is not in initialized state."; return false; } // Prepare connection, fail if this fails. if (!this->OnConnection()) { return false; } // Update state m_DeviceState = State_Connected; this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISCONNECTED, true); return true; } void mitk::USDevice::ConnectAsynchron() { this->m_MultiThreader->SpawnThread(this->ConnectThread, this); } bool mitk::USDevice::Disconnect() { if (!GetIsConnected()) { MITK_WARN << "Tried to disconnect an ultrasound device that was not " "connected. Ignoring call..."; return false; } // Prepare connection, fail if this fails. if (!this->OnDisconnection()) return false; // Update state m_DeviceState = State_Initialized; this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISCONNECTED, false); return true; } bool mitk::USDevice::Activate() { if (!this->GetIsConnected()) { MITK_INFO("mitkUSDevice") << "Cannot activate device if it is not in connected state."; return true; } if (OnActivation()) { m_DeviceState = State_Activated; m_FreezeBarrier = itk::ConditionVariable::New(); // spawn thread for aquire images if us device is active if (m_SpawnAcquireThread) { this->m_ThreadID = this->m_MultiThreader->SpawnThread(this->Acquire, this); } this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISACTIVE, true); this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_LABEL, this->GetServicePropertyLabel()); // initialize the b mode control properties of the micro service mitk::USControlInterfaceBMode::Pointer bmodeControls = this->GetControlInterfaceBMode(); if (bmodeControls.IsNotNull()) { bmodeControls->Initialize(); } } this->ProvideViaOIGTL(); return m_DeviceState == State_Activated; } void mitk::USDevice::ProvideViaOIGTL() { // create a new OpenIGTLink Server if (m_IGTLServer.IsNull()) m_IGTLServer = mitk::IGTLServer::New(true); m_IGTLServer->SetName(this->GetName()); // create a new OpenIGTLink Device source if (m_IGTLMessageProvider.IsNull()) m_IGTLMessageProvider = mitk::IGTLMessageProvider::New(); // set the OpenIGTLink server as the source for the device source m_IGTLMessageProvider->SetIGTLDevice(m_IGTLServer); // register the provider so that it can be configured with the IGTL manager // plugin. This could be hardcoded but now I already have the fancy plugin. m_IGTLMessageProvider->RegisterAsMicroservice(); m_ImageToIGTLMsgFilter = mitk::ImageToIGTLMessageFilter::New(); m_ImageToIGTLMsgFilter->ConnectTo(this); // set the name of this filter to identify it easier m_ImageToIGTLMsgFilter->SetName(this->GetName()); // register this filter as micro service. The message provider looks for // provided IGTLMessageSources, once it found this microservice and someone // requested this data type then the provider will connect with this filter // automatically. m_ImageToIGTLMsgFilter->RegisterAsMicroservice(); } void mitk::USDevice::Deactivate() { if (!this->GetIsActive()) { MITK_WARN("mitkUSDevice") << "Cannot deactivate a device which is not activae."; return; } if (!OnDeactivation()) { return; } DisableOIGTL(); m_DeviceState = State_Connected; this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISACTIVE, false); this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_LABEL, this->GetServicePropertyLabel()); } void mitk::USDevice::DisableOIGTL() { // TODO: This seems not to be enough cleanup to catch all cases. For example, if the device is disconnected // from the OIGTL GUI, this won't get cleaned up correctly. m_IGTLServer->CloseConnection(); m_IGTLMessageProvider->UnRegisterMicroservice(); m_ImageToIGTLMsgFilter->UnRegisterMicroservice(); } void mitk::USDevice::SetIsFreezed(bool freeze) { if (!this->GetIsActive()) { MITK_WARN("mitkUSDevice") << "Cannot freeze or unfreeze if device is not active."; return; } this->OnFreeze(freeze); if (freeze) { m_IsFreezed = true; } else { m_IsFreezed = false; // wake up the image acquisition thread m_FreezeBarrier->Signal(); } } bool mitk::USDevice::GetIsFreezed() { + /* if (!this->GetIsActive()) { MITK_WARN("mitkUSDevice")("mitkUSTelemedDevice") << "Cannot get freeze state if the hardware interface is not ready. " "Returning false..."; return false; - } + }*/ return m_IsFreezed; } void mitk::USDevice::PushFilter(AbstractOpenCVImageFilter::Pointer filter) { mitk::USImageSource::Pointer imageSource = this->GetUSImageSource(); if (imageSource.IsNull()) { MITK_ERROR << "ImageSource must not be null when pushing a filter."; mitkThrow() << "ImageSource must not be null when pushing a filter."; } imageSource->PushFilter(filter); } void mitk::USDevice::PushFilterIfNotPushedBefore( AbstractOpenCVImageFilter::Pointer filter) { mitk::USImageSource::Pointer imageSource = this->GetUSImageSource(); if (imageSource.IsNull()) { MITK_ERROR << "ImageSource must not be null when pushing a filter."; mitkThrow() << "ImageSource must not be null when pushing a filter."; } if (!imageSource->GetIsFilterInThePipeline(filter)) { imageSource->PushFilter(filter); } } bool mitk::USDevice::RemoveFilter(AbstractOpenCVImageFilter::Pointer filter) { mitk::USImageSource::Pointer imageSource = this->GetUSImageSource(); if (imageSource.IsNull()) { MITK_ERROR << "ImageSource must not be null when pushing a filter."; mitkThrow() << "ImageSource must not be null when removing a filter."; } return imageSource->RemoveFilter(filter); } void mitk::USDevice::UpdateServiceProperty(std::string key, std::string value) { m_ServiceProperties[key] = value; m_ServiceRegistration.SetProperties(m_ServiceProperties); // send event to notify listeners about the changed property m_PropertyChangedMessage(key, value); } void mitk::USDevice::UpdateServiceProperty(std::string key, double value) { std::stringstream stream; stream << value; this->UpdateServiceProperty(key, stream.str()); } void mitk::USDevice::UpdateServiceProperty(std::string key, bool value) { this->UpdateServiceProperty( key, value ? std::string("true") : std::string("false")); } /** mitk::Image* mitk::USDevice::GetOutput() { if (this->GetNumberOfOutputs() < 1) return nullptr; return static_cast(this->ProcessObject::GetPrimaryOutput()); } mitk::Image* mitk::USDevice::GetOutput(unsigned int idx) { if (this->GetNumberOfOutputs() < 1) return nullptr; return static_cast(this->ProcessObject::GetOutput(idx)); } void mitk::USDevice::GraftOutput(itk::DataObject *graft) { this->GraftNthOutput(0, graft); } void mitk::USDevice::GraftNthOutput(unsigned int idx, itk::DataObject *graft) { if ( idx >= this->GetNumberOfOutputs() ) { itkExceptionMacro(<<"Requested to graft output " << idx << " but this filter only has " << this->GetNumberOfOutputs() << " Outputs."); } if ( !graft ) { itkExceptionMacro(<<"Requested to graft output with a nullptr pointer object" ); } itk::DataObject* output = this->GetOutput(idx); if ( !output ) { itkExceptionMacro(<<"Requested to graft output that is a nullptr pointer" ); } // Call Graft on USImage to copy member data output->Graft( graft ); } */ void mitk::USDevice::GrabImage() { mitk::Image::Pointer image = this->GetUSImageSource()->GetNextImage(); m_ImageMutex->Lock(); this->SetImage(image); m_ImageMutex->Unlock(); // if (image.IsNotNull() && (image->GetGeometry()!=nullptr)){ // MITK_INFO << "Spacing: " << image->GetGeometry()->GetSpacing();} } //########### GETTER & SETTER ##################// bool mitk::USDevice::GetIsInitialized() { return m_DeviceState == State_Initialized; } bool mitk::USDevice::GetIsActive() { return m_DeviceState == State_Activated; } bool mitk::USDevice::GetIsConnected() { return m_DeviceState == State_Connected; } std::string mitk::USDevice::GetDeviceManufacturer() { return m_Manufacturer; } std::string mitk::USDevice::GetDeviceModel() { return m_Name; } std::string mitk::USDevice::GetDeviceComment() { return m_Comment; } void mitk::USDevice::GenerateData() { m_ImageMutex->Lock(); if (m_Image.IsNull() || !m_Image->IsInitialized()) { m_ImageMutex->Unlock(); return; } mitk::Image::Pointer output = this->GetOutput(); if (!output->IsInitialized() || output->GetDimension(0) != m_Image->GetDimension(0) || output->GetDimension(1) != m_Image->GetDimension(1) || output->GetDimension(2) != m_Image->GetDimension(2) || output->GetPixelType() != m_Image->GetPixelType()) { output->Initialize(m_Image->GetPixelType(), m_Image->GetDimension(), m_Image->GetDimensions()); } // copy contents of the given image into the member variable, slice after slice for (unsigned int sliceNumber = 0; sliceNumber < m_Image->GetDimension(2); ++sliceNumber) { if (m_Image->IsSliceSet(sliceNumber)) { mitk::ImageReadAccessor inputReadAccessor(m_Image, m_Image->GetSliceData(sliceNumber, 0, 0)); output->SetSlice(inputReadAccessor.GetData(), sliceNumber); } } output->SetGeometry(m_Image->GetGeometry()); m_ImageMutex->Unlock(); }; std::string mitk::USDevice::GetServicePropertyLabel() { std::string isActive; if (this->GetIsActive()) { isActive = " (Active)"; } else { isActive = " (Inactive)"; } // e.g.: Zonare MyLab5 (Active) return m_Manufacturer + " " + m_Name + isActive; } ITK_THREAD_RETURN_TYPE mitk::USDevice::Acquire(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct* pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; mitk::USDevice* device = (mitk::USDevice*)pInfo->UserData; while (device->GetIsActive()) { // lock this thread when ultrasound device is freezed if (device->m_IsFreezed) { itk::SimpleMutexLock* mutex = &(device->m_FreezeMutex); mutex->Lock(); if (device->m_FreezeBarrier.IsNotNull()) { device->m_FreezeBarrier->Wait(mutex); } } device->GrabImage(); } return ITK_THREAD_RETURN_VALUE; } ITK_THREAD_RETURN_TYPE mitk::USDevice::ConnectThread(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct* pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; mitk::USDevice* device = (mitk::USDevice*)pInfo->UserData; device->Connect(); return ITK_THREAD_RETURN_VALUE; } void mitk::USDevice::ProbeChanged(std::string probename) { this->UpdateServiceProperty(mitk::USDevice::GetPropertyKeys().US_PROPKEY_PROBES_SELECTED, probename); } void mitk::USDevice::DepthChanged(double depth) { this->UpdateServiceProperty(mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH, depth); } diff --git a/Modules/US/USModel/mitkUSDevice.h b/Modules/US/USModel/mitkUSDevice.h index a7ba223766..c2c316155c 100644 --- a/Modules/US/USModel/mitkUSDevice.h +++ b/Modules/US/USModel/mitkUSDevice.h @@ -1,470 +1,470 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKUSDevice_H_HEADER_INCLUDED_ #define MITKUSDevice_H_HEADER_INCLUDED_ // STL #include // MitkUS #include "mitkUSProbe.h" #include #include "mitkUSImageSource.h" // MitkIGTL #include "mitkIGTLMessageProvider.h" #include "mitkIGTLServer.h" #include "mitkIGTLDeviceSource.h" #include "mitkImageToIGTLMessageFilter.h" // MITK #include #include #include // ITK #include #include // Microservices #include #include #include // DEPRECATED #include "mitkUSImageMetadata.h" namespace itk { template class SmartPointer; } namespace mitk { class USAbstractControlInterface; class USControlInterfaceBMode; class USControlInterfaceProbes; class USControlInterfaceDoppler; /** * \brief A device holds information about it's model, make and the connected probes. It is the * common super class for all devices and acts as an image source for mitkUSImages. It is the base class * for all US Devices, and every new device should extend it. * * US Devices support output of calibrated images, i.e. images that include a specific geometry. * To achieve this, call SetCalibration, and make sure that the subclass also calls apply * transformation at some point (The USDevice does not automatically apply the transformation to the image) * * Note that USDevices will be removed from micro servive when their * destructor is called. Registering into micro service is done when * mitk::USDevice::Initialize() is called. * * \ingroup US */ class MITKUS_EXPORT USDevice : public mitk::ImageSource { public: enum DeviceStates { State_NoState, State_Initialized, State_Connected, State_Activated }; mitkClassMacro(USDevice, mitk::ImageSource); + itkSetMacro(SpawnAcquireThread, bool); + itkGetMacro(SpawnAcquireThread, bool); struct USImageCropArea { int cropLeft; int cropRight; int cropBottom; int cropTop; }; /** * \brief These constants are used in conjunction with Microservices. * The constants aren't defined as static member attributes to avoid the * "static initialization order fiasco", which would occur when objects of * this class are used in module activators (for restoring stored device, * for example). */ struct PropertyKeys { const std::string US_INTERFACE_NAME; // Common Interface name of all US Devices. Used to refer to this device via Microservices const std::string US_PROPKEY_MANUFACTURER; const std::string US_PROPKEY_NAME; const std::string US_PROPKEY_COMMENT; const std::string US_PROPKEY_LABEL; // Human readable text represntation of this device const std::string US_PROPKEY_ISCONNECTED; // Whether this device is connected or not. const std::string US_PROPKEY_ISACTIVE; // Whether this device is active or not. const std::string US_PROPKEY_CLASS; // Class Name of this Object const std::string US_PROPKEY_PROBES_SELECTED; const std::string US_PROPKEY_BMODE_FREQUENCY; const std::string US_PROPKEY_BMODE_POWER; const std::string US_PROPKEY_BMODE_DEPTH; const std::string US_PROPKEY_BMODE_GAIN; const std::string US_PROPKEY_BMODE_REJECTION; const std::string US_PROPKEY_BMODE_DYNAMIC_RANGE; PropertyKeys() : US_INTERFACE_NAME("org.mitk.services.UltrasoundDevice"), US_PROPKEY_MANUFACTURER(US_INTERFACE_NAME + ".manufacturer"), US_PROPKEY_NAME(US_INTERFACE_NAME + ".name"), US_PROPKEY_COMMENT(US_INTERFACE_NAME + ".comment"), US_PROPKEY_LABEL(US_INTERFACE_NAME + ".label"), US_PROPKEY_ISCONNECTED(US_INTERFACE_NAME + ".isConnected"), US_PROPKEY_ISACTIVE(US_INTERFACE_NAME + ".isActive"), US_PROPKEY_CLASS(US_INTERFACE_NAME + ".class"), US_PROPKEY_PROBES_SELECTED(US_INTERFACE_NAME + ".probes.selected"), US_PROPKEY_BMODE_FREQUENCY(US_INTERFACE_NAME + ".bmode.frequency"), US_PROPKEY_BMODE_POWER(US_INTERFACE_NAME + ".bmode.power"), US_PROPKEY_BMODE_DEPTH(US_INTERFACE_NAME + ".bmode.depth"), US_PROPKEY_BMODE_GAIN(US_INTERFACE_NAME + ".bmode.gain"), US_PROPKEY_BMODE_REJECTION(US_INTERFACE_NAME + ".bmode.rejection"), US_PROPKEY_BMODE_DYNAMIC_RANGE(US_INTERFACE_NAME + ".bmode.dynamicRange") {} }; /** * \brief Event for being notified about changes of the micro service properties. * This event can be used if no micro service context is available. */ mitkNewMessage2Macro(PropertyChanged, const std::string&, const std::string&) /** * \return keys for the microservice properties of ultrasound devices */ static mitk::USDevice::PropertyKeys GetPropertyKeys(); /** * \brief Default getter for the custom control interface. * Has to be implemented in a subclass if a custom control interface is * available. Default implementation returns null. * * \return null pointer */ virtual itk::SmartPointer GetControlInterfaceCustom(); /** * \brief Default getter for the b mode control interface. * Has to be implemented in a subclass if a b mode control interface is * available. Default implementation returns null. * * \return null pointer */ virtual itk::SmartPointer GetControlInterfaceBMode(); /** * \brief Default getter for the probes control interface. * Has to be implemented in a subclass if a probes control interface is * available. Default implementation returns null. * * \return null pointer */ virtual itk::SmartPointer GetControlInterfaceProbes(); /** * \brief Default getter for the doppler control interface. * Has to be implemented in a subclass if a doppler control interface is * available. Default implementation returns null. * * \return null pointer */ virtual itk::SmartPointer GetControlInterfaceDoppler(); /** * \brief Changes device state to mitk::USDevice::State_Initialized. * During initialization the virtual method * mitk::USDevice::OnInitialization will be called. If this method * returns false the initialization process will be canceled. Otherwise * the mitk::USDevice is registered in a micro service. */ bool Initialize(); /** * \brief Connects this device. A connected device is ready to deliver images (i.e. be Activated). A Connected Device can be active. A disconnected Device cannot be active. * Internally calls onConnect and then registers the device with the service. A device usually should * override the OnConnection() method, but never the Connect() method, since this will possibly exclude the device * from normal service management. The exact flow of events is: * 0. Check if the device is already connected. If yes, return true anyway, but don't do anything. * 1. Call OnConnection() Here, a device should establish it's connection with the hardware Afterwards, it should be ready to start transmitting images at any time. * 2. If OnConnection() returns true ("successful"), then the device is registered with the service. * 3. if not, it the method itself returns false or may throw an expection, depeneding on the device implementation. * */ bool Connect(); void ConnectAsynchron(); /** * \brief Works analogously to mitk::USDevice::Connect(). Don't override this Method, but onDisconnection instead. */ bool Disconnect(); /** * \brief Activates this device. * After the activation process, the device will start to produce images. * This Method will fail, if the device is not connected. */ bool Activate(); /** * \brief Deactivates this device. * After the deactivation process, the device will no longer produce * images, but still be connected. */ void Deactivate(); /** * \brief Can toggle if ultrasound image is currently updated or freezed. * * \param freeze true to stop updating the ultrasound image, false to start updating again */ virtual void SetIsFreezed(bool freeze); /** * \return true if device is currently freezed (no image update is done), false otherwise */ virtual bool GetIsFreezed(); void PushFilter(AbstractOpenCVImageFilter::Pointer filter); void PushFilterIfNotPushedBefore(AbstractOpenCVImageFilter::Pointer filter); bool RemoveFilter(AbstractOpenCVImageFilter::Pointer filter); /** * @brief To be called when the used probe changed. Will update the service properties * @param probename of the now used probe */ void ProbeChanged(std::string probename); /** * @brief To be called when the scanning depth of the probe changed. Will update the service properties * @param depth that is now used */ void DepthChanged(double depth); /** * \brief Given property is updated in the device micro service. * This method is mainly for being used by the control interface * superclasses. You do not need to call it by yoursefs in your * concrete control interface classes. */ void UpdateServiceProperty(std::string key, std::string value); void UpdateServiceProperty(std::string key, double value); void UpdateServiceProperty(std::string key, bool value); //########### GETTER & SETTER ##################// /** * \brief Returns the Class of the Device. This Method must be reimplemented by every Inheriting Class. */ virtual std::string GetDeviceClass() = 0; /** * \brief True, if the device object is created and initialized, false otherwise. */ bool GetIsInitialized(); /** * \brief True, if the device is currently generating image data, false otherwise. */ bool GetIsActive(); /** * \brief True, if the device is currently ready to start transmitting image data or is already * transmitting image data. A disconnected device cannot be activated. */ bool GetIsConnected(); /* @return Returns the area that will be cropped from the US image. Is disabled / [0,0,0,0] by default. */ mitk::USDevice::USImageCropArea GetCropArea(); /** @return Returns the current image source of this device. */ virtual USImageSource::Pointer GetUSImageSource() = 0; /** \brief Deprecated -> use GetManufacturer() instead */ DEPRECATED(std::string GetDeviceManufacturer()); /** \brief Deprecated -> use GetName() instead */ DEPRECATED(std::string GetDeviceModel()); /** \brief Deprecated -> use GetCommend() instead */ DEPRECATED(std::string GetDeviceComment()); itkGetMacro(Manufacturer, std::string); itkGetMacro(Name, std::string); itkGetMacro(Comment, std::string); void SetManufacturer(std::string manufacturer); void SetName(std::string name); void SetComment(std::string comment); itkGetMacro(DeviceState, DeviceStates) itkGetMacro(ServiceProperties, us::ServiceProperties) void GrabImage(); protected: itkSetMacro(Image, mitk::Image::Pointer); - itkSetMacro(SpawnAcquireThread, bool); - itkGetMacro(SpawnAcquireThread, bool); static ITK_THREAD_RETURN_TYPE Acquire(void* pInfoStruct); static ITK_THREAD_RETURN_TYPE ConnectThread(void* pInfoStruct); mitk::Image::Pointer m_Image; mitk::Image::Pointer m_OutputImage; /** * \brief Registers an OpenIGTLink device as a microservice so that we can send the images of * this device via the network. */ void ProvideViaOIGTL(); /** * \brief Deregisters the microservices for OpenIGTLink. */ void DisableOIGTL(); mitk::IGTLServer::Pointer m_IGTLServer; mitk::IGTLMessageProvider::Pointer m_IGTLMessageProvider; mitk::ImageToIGTLMessageFilter::Pointer m_ImageToIGTLMsgFilter; bool m_IsFreezed; DeviceStates m_DeviceState; /* @brief defines the area that should be cropped from the US image */ USImageCropArea m_CropArea; /** * \brief This Method constructs the service properties which can later be used to * register the object with the Microservices * Return service properties */ us::ServiceProperties ConstructServiceProperties(); /** * \brief Remove this device from the micro service. */ void UnregisterOnService(); /** * \brief Is called during the initialization process. * Override this method in a subclass to handle the actual initialization. * If it returns false, the initialization process will be canceled. * * \return true if successful and false if unsuccessful * \throw mitk::Exception implementation may throw an exception to clarify what went wrong */ virtual bool OnInitialization() = 0; /** * \brief Is called during the connection process. * Override this method in a subclass to handle the actual connection. * If it returns false, the connection process will be canceled. * * \return true if successful and false if unsuccessful * \throw mitk::Exception implementation may throw an exception to clarify what went wrong */ virtual bool OnConnection() = 0; /** * \brief Is called during the disconnection process. * Override this method in a subclass to handle the actual disconnection. * If it returns false, the disconnection process will be canceled. * * \return true if successful and false if unsuccessful * \throw mitk::Exception implementation may throw an exception to clarify what went wrong */ virtual bool OnDisconnection() = 0; /** * \brief Is called during the activation process. * After this method is finished, the device should be generating images. * If it returns false, the activation process will be canceled. * * \return true if successful and false if unsuccessful * \throw mitk::Exception implementation may throw an exception to clarify what went wrong */ virtual bool OnActivation() = 0; /** * \brief Is called during the deactivation process. * After a call to this method the device should still be connected, * but not producing images anymore. * * \return true if successful and false if unsuccessful * \throw mitk::Exception implementation may throw an exception to clarify what went wrong */ virtual bool OnDeactivation() = 0; /** * \brief Called when mitk::USDevice::SetIsFreezed() is called. * Subclasses can overwrite this method to do additional actions. Default * implementation does noting. */ virtual void OnFreeze(bool) { } /** * \brief Enforces minimal Metadata to be set. */ USDevice(std::string manufacturer, std::string model); /** * \brief Constructs a device with the given Metadata. Make sure the Metadata contains meaningful content! * \deprecated Use USDevice(std::string manufacturer, std::string model) instead. */ USDevice(mitk::USImageMetadata::Pointer metadata); virtual ~USDevice(); /** * \brief Grabs the next frame from the Video input. * This method is called internally, whenever Update() is invoked by an Output. */ virtual void GenerateData() override; std::string GetServicePropertyLabel(); private: std::string m_Manufacturer; std::string m_Name; std::string m_Comment; bool m_SpawnAcquireThread; /** * \brief The device's ServiceRegistration object that allows to modify it's Microservice registraton details. */ us::ServiceRegistration m_ServiceRegistration; /** * \brief Properties of the device's Microservice. */ us::ServiceProperties m_ServiceProperties; // Threading-Related itk::ConditionVariable::Pointer m_FreezeBarrier; itk::SimpleMutexLock m_FreezeMutex; itk::MultiThreader::Pointer m_MultiThreader; ///< itk::MultiThreader used for thread handling itk::FastMutexLock::Pointer m_ImageMutex; ///< mutex for images provided by the image source int m_ThreadID; ///< ID of the started thread bool m_UnregisteringStarted; }; } // namespace mitk // This is the microservice declaration. Do not meddle! MITK_DECLARE_SERVICE_INTERFACE(mitk::USDevice, "org.mitk.services.UltrasoundDevice") #endif // MITKUSDevice_H_HEADER_INCLUDED_ diff --git a/Modules/US/USNavigation/Testing/mitkCombinedModalityTest.cpp b/Modules/US/USNavigation/Testing/mitkCombinedModalityTest.cpp index 0556c322ba..f7dc20005a 100644 --- a/Modules/US/USNavigation/Testing/mitkCombinedModalityTest.cpp +++ b/Modules/US/USNavigation/Testing/mitkCombinedModalityTest.cpp @@ -1,180 +1,180 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkUSCombinedModality.h" #include #include #include #include class mitkCombinedModalityTestClass { public: /* * \brief Returns a reference string for serialized calibrations. */ static std::string GetSerializedReference() { return std::string("\n<") + mitk::USCombinedModality::DefaultProbeIdentifier + mitk::USCombinedModality::ProbeAndDepthSeperator + "0 M00=\"1.1234\" M01=\"1.2234\" M02=\"1.3234\" M10=\"1.4234\" M11=\"1.5234\" M12=\"1.6234\" M20=\"1.7234\" M21=\"1.8234\" M22=\"1.9234\" T0=\"2.1234\" T1=\"2.2234\" T2=\"2.3234\" />\n\n"; } static bool CompareDoubles (double A, double B) { float diff = A - B; return (diff < 0.0001) && (-diff < 0.0001); } /* * \brief Creates a dummy combined modality. */ static mitk::USCombinedModality::Pointer CreateModality() { mitk::USVideoDevice::Pointer usDevice = mitk::USVideoDevice::New("IllegalPath", "Manufacturer", "Model"); mitk::VirtualTrackingDevice::Pointer tracker = mitk::VirtualTrackingDevice::New(); tracker->AddTool("tool1"); tracker->AddTool("tool2"); mitk::TrackingDeviceSource::Pointer source = mitk::TrackingDeviceSource::New(); source->SetTrackingDevice(tracker); source->Connect(); source->StartTracking(); - return mitk::USCombinedModality::New(usDevice.GetPointer(), source.GetPointer(), "MBI", "EchoTrack"); + return mitk::USCombinedModality::New(usDevice.GetPointer(), source.GetPointer(), false); } static void TestInstantiation() { mitk::USCombinedModality::Pointer combinedModality = CreateModality(); MITK_TEST_CONDITION_REQUIRED(combinedModality.IsNotNull(), "CombinedModality should not be null after instantiation"); } static void TestSerialization() { mitk::USCombinedModality::Pointer modality = CreateModality(); mitk::AffineTransform3D::MatrixType matrix; matrix[0][0] = 1.1234; matrix[0][1] = 1.2234; matrix[0][2] = 1.3234; matrix[1][0] = 1.4234; matrix[1][1] = 1.5234; matrix[1][2] = 1.6234; matrix[2][0] = 1.7234; matrix[2][1] = 1.8234; matrix[2][2] = 1.9234; mitk::AffineTransform3D::OffsetType offset; offset[0] = 2.1234; offset[1] = 2.2234; offset[2] = 2.3234; mitk::AffineTransform3D::Pointer transform = mitk::AffineTransform3D::New(); transform->SetMatrix(matrix); transform->SetOffset(offset); modality->SetCalibration(transform); MITK_TEST_CONDITION_REQUIRED(modality->SerializeCalibration() == GetSerializedReference(), "Testing correct Serialization..."); } static void TestDeserialization() { mitk::USCombinedModality::Pointer modality = CreateModality(); modality->DeserializeCalibration(GetSerializedReference()); mitk::AffineTransform3D::Pointer transform = modality->GetCalibration(); mitk::AffineTransform3D::MatrixType matrix = transform->GetMatrix(); mitk::AffineTransform3D::OffsetType offset = transform->GetOffset();; bool identical = true; if (! CompareDoubles(matrix[0][0], 1.1234)) identical = false; if (! CompareDoubles(matrix[0][1], 1.2234)) identical = false; if (! CompareDoubles(matrix[0][2], 1.3234)) identical = false; if (! CompareDoubles(matrix[1][0], 1.4234)) identical = false; if (! CompareDoubles(matrix[1][1], 1.5234)) identical = false; if (! CompareDoubles(matrix[1][2], 1.6234)) identical = false; if (! CompareDoubles(matrix[2][0], 1.7234)) identical = false; if (! CompareDoubles(matrix[2][1], 1.8234)) identical = false; if (! CompareDoubles(matrix[2][2], 1.9234)) identical = false; if (! CompareDoubles(offset[0], 2.1234)) identical = false; if (! CompareDoubles(offset[1], 2.2234)) identical = false; if (! CompareDoubles(offset[2], 2.3234)) identical = false; MITK_TEST_CONDITION_REQUIRED(identical, "Testing if deserialized calibration is identical to serialized one..."); // test if invalid strings cause exceptions MITK_TEST_FOR_EXCEPTION(mitk::Exception, modality->DeserializeCalibration("invalid-string")); MITK_TEST_FOR_EXCEPTION(mitk::Exception, modality->DeserializeCalibration("", false)); } static void TestFilterPipeline() { /*mitk::USCombinedModality::Pointer combinedModality = mitkCombinedModalityTestClass::CreateModality(); MITK_INFO << combinedModality->GetNavigationDataSource()->GetNameOfClass(); MITK_TEST_CONDITION(strcmp(combinedModality->GetNavigationDataSource()->GetNameOfClass(), "TrackingDeviceSource") == 0, "")*/ mitk::USVideoDevice::Pointer usDevice = mitk::USVideoDevice::New("IllegalPath", "Manufacturer", "Model"); mitk::VirtualTrackingDevice::Pointer tracker = mitk::VirtualTrackingDevice::New(); tracker->AddTool("tool1"); tracker->AddTool("tool2"); mitk::TrackingDeviceSource::Pointer source = mitk::TrackingDeviceSource::New(); source->SetTrackingDevice(tracker); source->Connect(); source->StartTracking(); - mitk::USCombinedModality::Pointer modality = mitk::USCombinedModality::New(usDevice.GetPointer(), source.GetPointer(), "MBI", "EchoTrack"); + mitk::USCombinedModality::Pointer modality = mitk::USCombinedModality::New(usDevice.GetPointer(), source.GetPointer(), false); MITK_TEST_CONDITION(source->GetOutput(0) == modality->GetNavigationDataSource()->GetOutput(0), "Navigation data output of the Combined Modality should be the same as the source output as no filters are active.") modality->SetNumberOfSmoothingValues(2); mitk::NavigationDataSource::Pointer smoothingFilter = modality->GetNavigationDataSource(); MITK_TEST_CONDITION(source->GetOutput(0) != smoothingFilter->GetOutput(0), "Navigation data output of the Combined Modality should be different to the source output as smoothing filter is active.") modality->SetNumberOfSmoothingValues(0); MITK_TEST_CONDITION(source->GetOutput(0) == modality->GetNavigationDataSource()->GetOutput(0), "Navigation data output of the Combined Modality should be the same as the source output again.") modality->SetDelayCount(5); MITK_TEST_CONDITION(source->GetOutput(0) != smoothingFilter->GetOutput(0), "Navigation data output of the Combined Modality should be different to the source output as delay filter is active.") modality->SetDelayCount(0); MITK_TEST_CONDITION(source->GetOutput(0) == modality->GetNavigationDataSource()->GetOutput(0), "Navigation data output of the Combined Modality should be the same as the source output again.") } }; /** * This function is testing methods of the class USDevice. */ int mitkCombinedModalityTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("mitkCombinedModalityTest"); mitkCombinedModalityTestClass::TestInstantiation(); mitkCombinedModalityTestClass::TestSerialization(); mitkCombinedModalityTestClass::TestDeserialization(); mitkCombinedModalityTestClass::TestFilterPipeline(); MITK_TEST_END(); } diff --git a/Modules/US/USNavigation/files.cmake b/Modules/US/USNavigation/files.cmake index b240daaede..8d3a527324 100644 --- a/Modules/US/USNavigation/files.cmake +++ b/Modules/US/USNavigation/files.cmake @@ -1,5 +1,6 @@ SET(CPP_FILES mitkUSCombinedModality.cpp + mitkAbstractUltrasoundTrackerDevice.cpp Filter/mitkNodeDisplacementFilter.cpp ) diff --git a/Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.cpp b/Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.cpp new file mode 100644 index 0000000000..1afd8b41a6 --- /dev/null +++ b/Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.cpp @@ -0,0 +1,478 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkAbstractUltrasoundTrackerDevice.h" +#include "mitkImageReadAccessor.h" +#include "mitkNavigationDataSmoothingFilter.h" +#include "mitkNavigationDataDelayFilter.h" +#include "mitkTrackingDeviceSource.h" + +// US Control Interfaces +#include "mitkUSControlInterfaceProbes.h" +#include "mitkUSControlInterfaceBMode.h" +#include "mitkUSControlInterfaceDoppler.h" + +//Microservices +#include +#include +#include +#include + +#include + +//TempIncludes +#include + +//___ +//Microservices + +const std::string mitk::AbstractUltrasoundTrackerDevice::DeviceClassIdentifier = "org.mitk.modules.us.AbstractUltrasoundTrackerDevice"; +const char* mitk::AbstractUltrasoundTrackerDevice::DefaultProbeIdentifier = "default"; +const char* mitk::AbstractUltrasoundTrackerDevice::ProbeAndDepthSeperator = "_"; + +const std::string mitk::AbstractUltrasoundTrackerDevice::US_INTERFACE_NAME = "org.mitk.services.AbstractUltrasoundTrackerDevice"; +const std::string mitk::AbstractUltrasoundTrackerDevice::US_PROPKEY_DEVICENAME = US_INTERFACE_NAME + ".devicename"; +const std::string mitk::AbstractUltrasoundTrackerDevice::US_PROPKEY_CLASS = US_INTERFACE_NAME + ".class"; +const std::string mitk::AbstractUltrasoundTrackerDevice::US_PROPKEY_ID = US_INTERFACE_NAME + ".id"; +//____ + + +mitk::AbstractUltrasoundTrackerDevice::AbstractUltrasoundTrackerDevice( + USDevice::Pointer usDevice, NavigationDataSource::Pointer trackingDevice, + bool trackedUltrasoundActive ) : + m_UltrasoundDevice(usDevice), m_TrackingDeviceDataSource(trackingDevice), + m_SmoothingFilter(mitk::NavigationDataSmoothingFilter::New()), + m_DelayFilter(mitk::NavigationDataDelayFilter::New(0)), + m_NumberOfSmoothingValues(0), m_DelayCount(0), + m_IsTrackedUltrasoundActive( trackedUltrasoundActive ) +{ + this->RebuildFilterPipeline(); + + //create a new output (for the image data) + mitk::Image::Pointer newOutput = mitk::Image::New(); + this->SetNthOutput(0, newOutput); + + // Combined Modality should not spawn an own acquire thread, because + // image acquiring is done by the included us device + m_UltrasoundDevice->SetSpawnAcquireThread(false); +} + + +mitk::AbstractUltrasoundTrackerDevice::~AbstractUltrasoundTrackerDevice() +{ + if (m_ServiceRegistration != nullptr) + { + m_ServiceRegistration.Unregister(); + } + m_ServiceRegistration = 0; +} + +mitk::AffineTransform3D::Pointer + mitk::AbstractUltrasoundTrackerDevice::GetCalibration() +{ + return this->GetCalibration( this->GetCurrentDepthValue(), + this->GetIdentifierForCurrentProbe() ); +} + +mitk::AffineTransform3D::Pointer + mitk::AbstractUltrasoundTrackerDevice::GetCalibration(std::string depth) +{ + return this->GetCalibration(depth, this->GetIdentifierForCurrentProbe()); +} + +mitk::AffineTransform3D::Pointer + mitk::AbstractUltrasoundTrackerDevice::GetCalibration( std::string depth, + std::string probe ) +{ + // make sure that there is no '/' which would cause problems for TinyXML + std::replace(probe.begin(), probe.end(), '/', '-'); + + // create identifier for calibration from probe and depth + std::string calibrationKey = + probe + + mitk::AbstractUltrasoundTrackerDevice::ProbeAndDepthSeperator + + depth; + + // find calibration for combination of probe identifier and depth + std::map::iterator calibrationIterator + = m_Calibrations.find(calibrationKey); + + if (calibrationIterator == m_Calibrations.end()) { return 0; } + + return calibrationIterator->second; +} + +void mitk::AbstractUltrasoundTrackerDevice::SetCalibration( + mitk::AffineTransform3D::Pointer calibration ) +{ + if( calibration.IsNull() ) + { + MITK_WARN << "Null pointer passed to SetCalibration of mitk::USDevice. Ignoring call."; + return; + } + + std::string calibrationKey = this->GetIdentifierForCurrentCalibration(); + if( calibrationKey.empty() ) + { + MITK_WARN << "Could not get a key for the calibration -> Calibration cannot be set."; + return; + } + + m_Calibrations[calibrationKey] = calibration; +} + +bool mitk::AbstractUltrasoundTrackerDevice::RemoveCalibration() +{ + return this->RemoveCalibration( this->GetCurrentDepthValue(), + this->GetIdentifierForCurrentProbe() ); +} + +bool mitk::AbstractUltrasoundTrackerDevice::RemoveCalibration(std::string depth) +{ + return this->RemoveCalibration( depth, + this->GetIdentifierForCurrentProbe() ); +} + +bool mitk::AbstractUltrasoundTrackerDevice::RemoveCalibration( std::string depth, + std::string probe ) +{ + // make sure that there is no '/' which would cause problems for TinyXML + std::replace(probe.begin(), probe.end(), '/', '-'); + + // create identifier for calibration from probe and depth + std::string calibrationKey = + probe + + mitk::AbstractUltrasoundTrackerDevice::ProbeAndDepthSeperator + + depth; + + return m_Calibrations.erase(calibrationKey) > 0; +} + +std::string mitk::AbstractUltrasoundTrackerDevice::GetDeviceClass() +{ + return DeviceClassIdentifier; +} + +mitk::USImageSource::Pointer mitk::AbstractUltrasoundTrackerDevice::GetUSImageSource() +{ + if (m_UltrasoundDevice.IsNull()) + { + MITK_ERROR("AbstractUltrasoundTrackerDevice")("USDevice") << "UltrasoundDevice must not be null."; + mitkThrow() << "UltrasoundDevice must not be null."; + } + + return m_UltrasoundDevice->GetUSImageSource(); +} + +mitk::NavigationDataSource::Pointer mitk::AbstractUltrasoundTrackerDevice::GetNavigationDataSource() +{ + return this->RebuildFilterPipeline(); +} + +bool mitk::AbstractUltrasoundTrackerDevice::GetIsCalibratedForCurrentStatus() +{ + return m_Calibrations.find(this->GetIdentifierForCurrentCalibration()) != m_Calibrations.end(); +} + +bool mitk::AbstractUltrasoundTrackerDevice::GetContainsAtLeastOneCalibration() +{ + return !m_Calibrations.empty(); +} + +std::string mitk::AbstractUltrasoundTrackerDevice::SerializeCalibration() +{ + std::stringstream result; + result << "" << std::endl; + // For each calibration in the set + for( std::map::iterator it = m_Calibrations.begin(); + it != m_Calibrations.end(); it++ ) + { + mitk::AffineTransform3D::MatrixType matrix = it->second->GetMatrix(); + mitk::AffineTransform3D::TranslationType translation = it->second->GetTranslation(); + TiXmlElement elem(it->first); + // Serialize Matrix + elem.SetDoubleAttribute("M00", matrix[0][0]); + elem.SetDoubleAttribute("M01", matrix[0][1]); + elem.SetDoubleAttribute("M02", matrix[0][2]); + elem.SetDoubleAttribute("M10", matrix[1][0]); + elem.SetDoubleAttribute("M11", matrix[1][1]); + elem.SetDoubleAttribute("M12", matrix[1][2]); + elem.SetDoubleAttribute("M20", matrix[2][0]); + elem.SetDoubleAttribute("M21", matrix[2][1]); + elem.SetDoubleAttribute("M22", matrix[2][2]); + // Serialize Offset + elem.SetDoubleAttribute("T0", translation[0]); + elem.SetDoubleAttribute("T1", translation[1]); + elem.SetDoubleAttribute("T2", translation[2]); + + result << elem << std::endl; + } + result << "" << std::endl; + + return result.str(); +} + +void mitk::AbstractUltrasoundTrackerDevice::DeserializeCalibration( + const std::string& xmlString, + bool clearPreviousCalibrations ) +{ + // Sanitize Input + if (xmlString == "") + { + MITK_ERROR << "Empty string passed to Deserialize() method of CombinedModality. Aborting..."; + mitkThrow() << "Empty string passed to Deserialize() method of CombinedModality. Aborting..."; + return; + } + // Clear previous calibrations if necessary + if (clearPreviousCalibrations) m_Calibrations.clear(); + + // Parse Input + TiXmlDocument doc; + if (!doc.Parse(xmlString.c_str())) + { + MITK_ERROR << "Unable to deserialize calibrations in CombinedModality. Error was: " << doc.ErrorDesc(); + mitkThrow() << "Unable to deserialize calibrations in CombinedModality. Error was: " << doc.ErrorDesc(); + return; + } + TiXmlElement* root = doc.FirstChildElement(); + if (root == nullptr) + { + MITK_ERROR << "Unable to deserialize calibrations in CombinedModality. String contained no root element."; + mitkThrow() << "Unable to deserialize calibrations in CombinedModality. String contained no root element."; + return; + } + // Read Calibrations + for (TiXmlElement* elem = root->FirstChildElement(); elem != nullptr; elem = elem->NextSiblingElement()) + { + mitk::AffineTransform3D::MatrixType matrix; + mitk::AffineTransform3D::OffsetType translation; + + std::string calibName = elem->Value(); + + // Deserialize Matrix + elem->QueryDoubleAttribute("M00", &matrix[0][0]); + elem->QueryDoubleAttribute("M01", &matrix[0][1]); + elem->QueryDoubleAttribute("M02", &matrix[0][2]); + elem->QueryDoubleAttribute("M10", &matrix[1][0]); + elem->QueryDoubleAttribute("M11", &matrix[1][1]); + elem->QueryDoubleAttribute("M12", &matrix[1][2]); + elem->QueryDoubleAttribute("M20", &matrix[2][0]); + elem->QueryDoubleAttribute("M21", &matrix[2][1]); + elem->QueryDoubleAttribute("M22", &matrix[2][2]); + + // Deserialize Offset + elem->QueryDoubleAttribute("T0", &translation[0]); + elem->QueryDoubleAttribute("T1", &translation[1]); + elem->QueryDoubleAttribute("T2", &translation[2]); + + mitk::AffineTransform3D::Pointer calibration = mitk::AffineTransform3D::New(); + calibration->SetMatrix(matrix); + calibration->SetTranslation(translation); + m_Calibrations[calibName] = calibration; + } +} + +void mitk::AbstractUltrasoundTrackerDevice::SetNumberOfSmoothingValues( + unsigned int numberOfSmoothingValues ) +{ + unsigned int oldNumber = m_NumberOfSmoothingValues; + m_NumberOfSmoothingValues = numberOfSmoothingValues; + + // if filter should be activated or deactivated + if ((oldNumber == 0 && numberOfSmoothingValues != 0) || + (oldNumber != 0 && numberOfSmoothingValues == 0)) + { + this->RebuildFilterPipeline(); + } + m_SmoothingFilter->SetNumerOfValues(numberOfSmoothingValues); +} + +void mitk::AbstractUltrasoundTrackerDevice::SetDelayCount( unsigned int delayCount ) +{ + unsigned int oldCount = m_DelayCount; + m_DelayCount = delayCount; + + // if filter should be activated or deactivated + if ((oldCount == 0 && delayCount != 0) || + (oldCount != 0 && delayCount == 0)) + { + this->RebuildFilterPipeline(); + } + m_DelayFilter->SetDelay(delayCount); +} + +itk::SmartPointer mitk::AbstractUltrasoundTrackerDevice::GetControlInterfaceCustom() +{ + return itk::SmartPointer(); +} + +itk::SmartPointer mitk::AbstractUltrasoundTrackerDevice::GetControlInterfaceBMode() +{ + return itk::SmartPointer(); +} + +itk::SmartPointer mitk::AbstractUltrasoundTrackerDevice::GetControlInterfaceProbes() +{ + return itk::SmartPointer(); +} + +itk::SmartPointer mitk::AbstractUltrasoundTrackerDevice::GetControlInterfaceDoppler() +{ + return itk::SmartPointer(); +} + +/*void mitk::AbstractUltrasoundTrackerDevice::UnregisterOnService() +{ + if( m_UltrasoundDevice->GetDeviceState() == USDevice::State_Activated ) + { + m_UltrasoundDevice->Deactivate(); + } + if( m_UltrasoundDevice->GetDeviceState() == USDevice::State_Connected ) + { + m_UltrasoundDevice->Disconnect(); + } + + if( m_ServiceRegistration != nullptr ) + m_ServiceRegistration.Unregister(); + m_ServiceRegistration = 0; +} + +void mitk::AbstractUltrasoundTrackerDevice::RegisterAsMicroservice() +{ + //Get Context + us::ModuleContext* context = us::GetModuleContext(); + + //Define ServiceProps + //us::ServiceProperties props; + mitk::UIDGenerator uidGen = + mitk::UIDGenerator("TEST", 16); + m_ServiceProperties[US_PROPKEY_ID] = uidGen.GetUID(); + m_ServiceProperties[US_PROPKEY_DEVICENAME] = m_UltrasoundDevice->GetName(); + m_ServiceProperties[US_PROPKEY_CLASS] = mitk::AbstractUltrasoundTrackerDevice::DeviceClassIdentifier; + + m_ServiceRegistration = context->RegisterService(this, m_ServiceProperties); +}*/ + +void mitk::AbstractUltrasoundTrackerDevice::GenerateData() +{ +} + + +std::string mitk::AbstractUltrasoundTrackerDevice::GetIdentifierForCurrentCalibration() +{ + return this->GetIdentifierForCurrentProbe() + + mitk::AbstractUltrasoundTrackerDevice::ProbeAndDepthSeperator + + this->GetCurrentDepthValue(); +} + +std::string mitk::AbstractUltrasoundTrackerDevice::GetIdentifierForCurrentProbe() +{ + us::ServiceProperties usdeviceProperties = m_UltrasoundDevice->GetServiceProperties(); + + us::ServiceProperties::const_iterator probeIt = usdeviceProperties.find( + mitk::USDevice::GetPropertyKeys().US_PROPKEY_PROBES_SELECTED); + + // get probe identifier from control interface for probes + std::string probeName = mitk::AbstractUltrasoundTrackerDevice::DefaultProbeIdentifier; + if (probeIt != usdeviceProperties.end()) + { + probeName = (probeIt->second).ToString(); + } + + // make sure that there is no '/' which would cause problems for TinyXML + std::replace(probeName.begin(), probeName.end(), '/', '-'); + + return probeName; +} + +std::string mitk::AbstractUltrasoundTrackerDevice::GetCurrentDepthValue() +{ + us::ServiceProperties usdeviceProperties = m_UltrasoundDevice->GetServiceProperties(); + + // get string for depth value from the micro service properties + std::string depth; + us::ServiceProperties::iterator depthIterator = usdeviceProperties.find( + mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH); + + if (depthIterator != usdeviceProperties.end()) + { + depth = depthIterator->second.ToString(); + } + else + { + depth = "0"; + } + + return depth; +} + +mitk::NavigationDataSource::Pointer mitk::AbstractUltrasoundTrackerDevice::RebuildFilterPipeline() +{ + itk::SmartPointer filter = m_TrackingDeviceDataSource; + + if( m_NumberOfSmoothingValues > 0 ) + { + for (unsigned int i = 0; i < m_TrackingDeviceDataSource->GetNumberOfOutputs(); i++) + { + m_SmoothingFilter->SetInput(i, filter->GetOutput(i)); + } + filter = m_SmoothingFilter; + } + + if( m_DelayCount > 0 ) + { + for( unsigned int i = 0; i < m_TrackingDeviceDataSource->GetNumberOfOutputs(); i++ ) + { + m_DelayFilter->SetInput(i, filter->GetOutput(i)); + } + filter = m_DelayFilter; + } + + return filter.GetPointer(); +} + +void mitk::AbstractUltrasoundTrackerDevice::UnregisterOnService() +{ + if (m_UltrasoundDevice->GetDeviceState() == USDevice::State_Activated) + { + m_UltrasoundDevice->Deactivate(); + } + if (m_UltrasoundDevice->GetDeviceState() == USDevice::State_Connected) + { + m_UltrasoundDevice->Disconnect(); + } + + if (m_ServiceRegistration != nullptr) + m_ServiceRegistration.Unregister(); + m_ServiceRegistration = 0; +} + +void mitk::AbstractUltrasoundTrackerDevice::RegisterAsMicroservice() +{ + //Get Context + us::ModuleContext* context = us::GetModuleContext(); + + //Define ServiceProps + //us::ServiceProperties props; + mitk::UIDGenerator uidGen = + mitk::UIDGenerator("org.mitk.services.AbstractUltrasoundTrackerDevice", 16); + m_ServiceProperties[US_PROPKEY_ID] = uidGen.GetUID(); + m_ServiceProperties[US_PROPKEY_DEVICENAME] = m_UltrasoundDevice->GetName(); + m_ServiceProperties[US_PROPKEY_CLASS] = mitk::AbstractUltrasoundTrackerDevice::DeviceClassIdentifier; + + m_ServiceRegistration = context->RegisterService(this, m_ServiceProperties); +} diff --git a/Modules/US/USNavigation/mitkUSCombinedModality.h b/Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.h similarity index 57% copy from Modules/US/USNavigation/mitkUSCombinedModality.h copy to Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.h index dea4bc126d..e8bc035359 100644 --- a/Modules/US/USNavigation/mitkUSCombinedModality.h +++ b/Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.h @@ -1,270 +1,261 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#ifndef MITKUSCombinedModality_H_HEADER_INCLUDED_ -#define MITKUSCombinedModality_H_HEADER_INCLUDED_ +#ifndef __mitkAbstractUltrasoundTrackerDevice_h +#define __mitkAbstractUltrasoundTrackerDevice_h #include #include "mitkUSDevice.h" +#include "mitkImageSource.h" #include "mitkNavigationDataSource.h" // Microservices #include #include +#include +#include +#include +#include namespace itk { template class SmartPointer; } namespace mitk { class NavigationDataSmoothingFilter; class NavigationDataDelayFilter; - class USControlInterfaceBMode; - class USControlInterfaceProbes; - class USControlInterfaceDoppler; /** - * \brief Combination of USDevice and NavigationDataSource. - * This class can be used as any USDevice subclass. Additionally tracking data be - * retrieved from the NavigationDataSource returned by GetTrackingDevice(). - * - * A calibration of the ultrasound image stream to the navigation datas can be set - * for the currently active zoom level (of the ultrasound device) by SetCalibration(). - * The ultrasound images are transformed according to this calibration in the - * GenerateData() method. - */ - class MITKUSNAVIGATION_EXPORT USCombinedModality : public USDevice + * \brief Abstract class for an easy handling of a combination of an USDevice and + * a NavigationDataSource. + * This class can be used as an ImageSource subclass. Additionally tracking data be + * retrieved from the NavigationDataSource returned by GetTrackingDevice(). + * + * A calibration of the ultrasound image stream to the navigation datas can be set + * for the currently active zoom level (of the ultrasound device) by SetCalibration() + * The ultrasound images are transformed according to this calibration in the + * GenerateData() method. + */ + + class MITKUSNAVIGATION_EXPORT AbstractUltrasoundTrackerDevice : public mitk::ImageSource { public: + static const std::string DeviceClassIdentifier; static const char* DefaultProbeIdentifier; static const char* ProbeAndDepthSeperator; + static const std::string US_INTERFACE_NAME; + static const std::string US_PROPKEY_DEVICENAME; + static const std::string US_PROPKEY_CLASS; + static const std::string US_PROPKEY_ID; - mitkClassMacro(USCombinedModality, USDevice); - mitkNewMacro4Param(USCombinedModality, USDevice::Pointer, itk::SmartPointer, std::string, std::string); + + mitkClassMacro(AbstractUltrasoundTrackerDevice, mitk::ImageSource); + mitkNewMacro3Param(AbstractUltrasoundTrackerDevice, USDevice::Pointer, itk::SmartPointer, bool); itkGetMacro(UltrasoundDevice, itk::SmartPointer); itkSetMacro(UltrasoundDevice, itk::SmartPointer); - itkGetMacro(TrackingDevice, itk::SmartPointer); - itkSetMacro(TrackingDevice, itk::SmartPointer); + itkGetMacro(TrackingDeviceDataSource, itk::SmartPointer); + itkSetMacro(TrackingDeviceDataSource, itk::SmartPointer); /** * \brief Getter for calibration data of the currently active depth and probe. * * \return Transformation for calibration or null if no calibration is available. */ AffineTransform3D::Pointer GetCalibration(); /** - * \brief Getter for calibration data of the given depth and the currently active probe. - * - * \param depth depth of the b mode ultrasound image for which the calibration should be returned - * \return Transformation for calibration or null if no calibration is available. - */ + * \brief Getter for calibration data of the given depth and the currently active probe. + * + * \param depth depth of the b mode ultrasound image for which the calibration should be returned + * \return Transformation for calibration or null if no calibration is available. + */ AffineTransform3D::Pointer GetCalibration(std::string depth); /** - * \brief Getter for calibration data of the given depth and probe. - * - * \param depth depth of the b mode ultrasound image for which the calibration should be returned - * \param probe probe of the ultrasound device for which the calibration should be returned - * \return Transformation for calibration or null if no calibration is available. - */ + * \brief Getter for calibration data of the given depth and probe. + * + * \param depth depth of the b mode ultrasound image for which the calibration should be returned + * \param probe probe of the ultrasound device for which the calibration should be returned + * \return Transformation for calibration or null if no calibration is available. + */ AffineTransform3D::Pointer GetCalibration(std::string depth, std::string probe); /** * \brief Sets a transformation as calibration data. * Calibration data is set for the currently activated probe and their current * zoom factor. It also marks the device as calibrated. */ void SetCalibration(AffineTransform3D::Pointer calibration); /** - * \brief Removes the calibration data of the currently active depth and probe. - * \return true on success, false if there was no calibration - */ + * \brief Removes the calibration data of the currently active depth and probe. + * \return true on success, false if there was no calibration + */ bool RemoveCalibration(); /** - * \brief Removes the calibration data of the given depth and the currently active probe. - * - * \param depth depth of the b mode ultrasound image for which the calibration should be removed - * \return true on success, false if there was no calibration - */ + * \brief Removes the calibration data of the given depth and the currently active probe. + * + * \param depth depth of the b mode ultrasound image for which the calibration should be removed + * \return true on success, false if there was no calibration + */ bool RemoveCalibration(std::string depth); /** - * \brief Removes the calibration data of the given depth and probe. - * - * \param depth depth of the b mode ultrasound image for which the calibration should be removed - * \param probe probe of the ultrasound device for which the calibration should be removed - * \return true on success, false if there was no calibration - */ + * \brief Removes the calibration data of the given depth and probe. + * + * \param depth depth of the b mode ultrasound image for which the calibration should be removed + * \param probe probe of the ultrasound device for which the calibration should be removed + * \return true on success, false if there was no calibration + */ bool RemoveCalibration(std::string depth, std::string probe); /** * \brief Returns the Class of the Device. */ - virtual std::string GetDeviceClass() override; + std::string GetDeviceClass(); /** * \brief Wrapper for returning USImageSource of the UltrasoundDevice. */ - virtual USImageSource::Pointer GetUSImageSource() override; - - /** - * \brief Wrapper for returning custom control interface of the UltrasoundDevice. - */ - virtual itk::SmartPointer GetControlInterfaceCustom() override; + USImageSource::Pointer GetUSImageSource(); - /** - * \brief Wrapper for returning B mode control interface of the UltrasoundDevice. - */ - virtual itk::SmartPointer GetControlInterfaceBMode() override; - - /** - * \brief Wrapper for returning probes control interface of the UltrasoundDevice. - */ - virtual itk::SmartPointer GetControlInterfaceProbes() override; + itk::SmartPointer GetNavigationDataSource(); /** - * \brief Wrapper for returning doppler control interface of the UltrasoundDevice. + * \return true if the device is calibrated for the currently selected probe with the current zoom level */ - virtual itk::SmartPointer GetControlInterfaceDoppler() override; - - virtual itk::SmartPointer GetNavigationDataSource(); - - /** - * \return true if the device is calibrated for the currently selected probe with the current zoom level - */ bool GetIsCalibratedForCurrentStatus(); /** - * \return true if a calibration was loaded for at least one probe and depth - */ - bool GetContainsAtLeastOneCalibration(); - - /** - * \brief Remove this device from the micro service. - * This method is public for mitk::USCombinedModality, because this devices - * can be completly removed. This is not possible for API devices, which - * should be available while their sub module is loaded. + * \return true if a calibration was loaded for at least one probe and depth */ - void UnregisterOnService(); + bool GetContainsAtLeastOneCalibration(); /** * \brief Serializes all contained calibrations into an xml fragment. * * The returned string contains one parent node named "calibrations" and several * subnodes, one for each calibration that is present. */ std::string SerializeCalibration(); /** * \brief Deserializes a string provided by a prior call to Serialize(). * If the bool flag is true, all prior calibrations will be deleted. * If the flag is set to false, prior calibrations will be retained, but overwritten * if one of equal name is present. * * \throws mitk::Exception if the given string could not be parsed correctly. */ void DeserializeCalibration(const std::string &xmlString, bool clearPreviousCalibrations = true); void SetNumberOfSmoothingValues(unsigned int numberOfSmoothingValues); void SetDelayCount(unsigned int delayCount); - void RegisterAsMicroservice(); - /** - *\brief These Constants are used in conjunction with Microservices + * \brief Remove this device from the micro service. + * This method is public for mitk::USCombinedModality, because this devices + * can be completly removed. This is not possible for API devices, which + * should be available while their sub module is loaded. */ - static const std::string US_INTERFACE_NAME; - static const std::string US_PROPKEY_DEVICENAME; - static const std::string US_PROPKEY_CLASS; - static const std::string US_PROPKEY_ID; - protected: - USCombinedModality(USDevice::Pointer usDevice, itk::SmartPointer trackingDevice, std::string manufacturer = "", std::string model = ""); - virtual ~USCombinedModality(); + void UnregisterOnService(); - /** - * \brief Initializes UltrasoundDevice. - */ - virtual bool OnInitialization() override; + virtual void RegisterAsMicroservice(); /** - * \brief Connects UltrasoundDevice. + * \brief Wrapper for returning custom control interface of the UltrasoundDevice. */ - virtual bool OnConnection() override; + virtual itk::SmartPointer GetControlInterfaceCustom(); /** - * \brief Disconnects UltrasoundDevice. + * \brief Wrapper for returning B mode control interface of the UltrasoundDevice. */ - virtual bool OnDisconnection() override; + virtual itk::SmartPointer GetControlInterfaceBMode(); /** - * \brief Activates UltrasoundDevice. + * \brief Wrapper for returning probes control interface of the UltrasoundDevice. */ - virtual bool OnActivation() override; + virtual itk::SmartPointer GetControlInterfaceProbes(); /** - * \brief Deactivates UltrasoundDevice. + * \brief Wrapper for returning doppler control interface of the UltrasoundDevice. */ - virtual bool OnDeactivation() override; + virtual itk::SmartPointer GetControlInterfaceDoppler(); /** - * \brief Freezes or unfreezes UltrasoundDevice. + *\brief These Constants are used in conjunction with Microservices */ - virtual void OnFreeze(bool) override; + /*static const std::string US_INTERFACE_NAME; + static const std::string US_PROPKEY_DEVICENAME; + static const std::string US_PROPKEY_CLASS; + static const std::string US_PROPKEY_ID;*/ + + protected: + AbstractUltrasoundTrackerDevice( USDevice::Pointer usDevice, + itk::SmartPointer trackingDevice, + bool trackedUltrasoundActive ); + virtual ~AbstractUltrasoundTrackerDevice(); + + itkGetMacro(IsTrackedUltrasoundActive, bool); /** * \brief Grabs the next frame from the input. + * Must be implemented by the derived class. * This method is called internally, whenever Update() is invoked by an Output. */ - void GenerateData() override; + virtual void GenerateData() override; std::string GetIdentifierForCurrentCalibration(); std::string GetIdentifierForCurrentProbe(); std::string GetCurrentDepthValue(); - void RebuildFilterPipeline(); + itk::SmartPointer RebuildFilterPipeline(); USDevice::Pointer m_UltrasoundDevice; - itk::SmartPointer m_TrackingDevice; + itk::SmartPointer m_TrackingDeviceDataSource; std::map m_Calibrations; itk::SmartPointer m_SmoothingFilter; itk::SmartPointer m_DelayFilter; - itk::SmartPointer m_LastFilter; unsigned int m_NumberOfSmoothingValues; unsigned int m_DelayCount; - private: /** * \brief The device's ServiceRegistration object that allows to modify it's Microservice registraton details. */ us::ServiceRegistration m_ServiceRegistration; /** * \brief Properties of the device's Microservice. */ us::ServiceProperties m_ServiceProperties; + + private: + + + bool m_IsTrackedUltrasoundActive; }; + } // namespace mitk -MITK_DECLARE_SERVICE_INTERFACE(mitk::USCombinedModality, "org.mitk.services.USCombinedModality") -#endif // MITKUSCombinedModality_H_HEADER_INCLUDED_ +MITK_DECLARE_SERVICE_INTERFACE(mitk::AbstractUltrasoundTrackerDevice, "org.mitk.services.AbstractUltrasoundTrackerDevice") + +#endif diff --git a/Modules/US/USNavigation/mitkUSCombinedModality.cpp b/Modules/US/USNavigation/mitkUSCombinedModality.cpp index 0ddbef3fea..400a3a073d 100644 --- a/Modules/US/USNavigation/mitkUSCombinedModality.cpp +++ b/Modules/US/USNavigation/mitkUSCombinedModality.cpp @@ -1,581 +1,262 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkUSCombinedModality.h" -#include "mitkUSDevice.h" -#include "mitkNavigationDataSource.h" +//#include "mitkNavigationDataSource.h" #include "mitkImageReadAccessor.h" #include #include #include "mitkTrackingDeviceSource.h" // US Control Interfaces #include "mitkUSControlInterfaceProbes.h" #include "mitkUSControlInterfaceBMode.h" #include "mitkUSControlInterfaceDoppler.h" -//Microservices -#include -#include -#include -#include -#include -//TempIncludes -#include -const std::string mitk::USCombinedModality::DeviceClassIdentifier = "org.mitk.modules.us.USCombinedModality"; -const char* mitk::USCombinedModality::DefaultProbeIdentifier = "default"; -const char* mitk::USCombinedModality::ProbeAndDepthSeperator = "_"; - -const std::string mitk::USCombinedModality::US_INTERFACE_NAME = "org.mitk.services.USCombinedModality"; -const std::string mitk::USCombinedModality::US_PROPKEY_DEVICENAME = US_INTERFACE_NAME + ".devicename"; -const std::string mitk::USCombinedModality::US_PROPKEY_CLASS = US_INTERFACE_NAME + ".class"; -const std::string mitk::USCombinedModality::US_PROPKEY_ID = US_INTERFACE_NAME + ".id"; - -mitk::USCombinedModality::USCombinedModality(USDevice::Pointer usDevice, NavigationDataSource::Pointer trackingDevice, std::string manufacturer, std::string model) - : mitk::USDevice(manufacturer, model), m_UltrasoundDevice(usDevice), m_TrackingDevice(trackingDevice), - m_SmoothingFilter(mitk::NavigationDataSmoothingFilter::New()), m_DelayFilter(mitk::NavigationDataDelayFilter::New(0)), - m_NumberOfSmoothingValues(0), m_DelayCount(0) +mitk::USCombinedModality::USCombinedModality( USDevice::Pointer usDevice, + NavigationDataSource::Pointer trackingDevice, + bool trackedUltrasoundActive ) + : AbstractUltrasoundTrackerDevice( usDevice, trackingDevice, trackedUltrasoundActive ) { - this->RebuildFilterPipeline(); - //create a new output (for the image data) - mitk::Image::Pointer newOutput = mitk::Image::New(); - this->SetNthOutput(0, newOutput); - - // Combined Modality should not spawn an own acquire thread, because - // image acquiring is done by the included us device - this->SetSpawnAcquireThread(false); } mitk::USCombinedModality::~USCombinedModality() { - if (m_ServiceRegistration != nullptr) - m_ServiceRegistration.Unregister(); - m_ServiceRegistration = 0; -} -std::string mitk::USCombinedModality::GetDeviceClass() -{ - return DeviceClassIdentifier; } - -mitk::USImageSource::Pointer mitk::USCombinedModality::GetUSImageSource() +/* +void mitk::USCombinedModality::RegisterAsMicroservice() { - if (m_UltrasoundDevice.IsNull()) - { - MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; - mitkThrow() << "UltrasoundDevice must not be null."; - } + //Get Context + us::ModuleContext* context = us::GetModuleContext(); + + //Define ServiceProps + //us::ServiceProperties props; + mitk::UIDGenerator uidGen = + mitk::UIDGenerator("org.mitk.services.AbstractUltrasoundTrackerDevice", 16); + m_ServiceProperties[US_PROPKEY_ID] = uidGen.GetUID(); + m_ServiceProperties[US_PROPKEY_DEVICENAME] = m_UltrasoundDevice->GetName(); + m_ServiceProperties[US_PROPKEY_CLASS] = mitk::AbstractUltrasoundTrackerDevice::DeviceClassIdentifier; + + m_ServiceRegistration = context->RegisterService(this, m_ServiceProperties); +}*/ + - return m_UltrasoundDevice->GetUSImageSource(); -} mitk::USAbstractControlInterface::Pointer mitk::USCombinedModality::GetControlInterfaceCustom() { if (m_UltrasoundDevice.IsNull()) { MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; mitkThrow() << "UltrasoundDevice must not be null."; } return m_UltrasoundDevice->GetControlInterfaceCustom(); } mitk::USControlInterfaceBMode::Pointer mitk::USCombinedModality::GetControlInterfaceBMode() { if (m_UltrasoundDevice.IsNull()) { MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; mitkThrow() << "UltrasoundDevice must not be null."; } return m_UltrasoundDevice->GetControlInterfaceBMode(); } mitk::USControlInterfaceProbes::Pointer mitk::USCombinedModality::GetControlInterfaceProbes() { if (m_UltrasoundDevice.IsNull()) { MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; mitkThrow() << "UltrasoundDevice must not be null."; } return m_UltrasoundDevice->GetControlInterfaceProbes(); } mitk::USControlInterfaceDoppler::Pointer mitk::USCombinedModality::GetControlInterfaceDoppler() { if (m_UltrasoundDevice.IsNull()) { MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; mitkThrow() << "UltrasoundDevice must not be null."; } return m_UltrasoundDevice->GetControlInterfaceDoppler(); } -void mitk::USCombinedModality::UnregisterOnService() -{ - if (m_DeviceState == State_Activated) { this->Deactivate(); } - if (m_DeviceState == State_Connected) { this->Disconnect(); } - - if (m_ServiceRegistration != nullptr) - m_ServiceRegistration.Unregister(); - m_ServiceRegistration = 0; -} -mitk::AffineTransform3D::Pointer mitk::USCombinedModality::GetCalibration() -{ - return this->GetCalibration(this->GetCurrentDepthValue(), this->GetIdentifierForCurrentProbe()); -} - -mitk::AffineTransform3D::Pointer mitk::USCombinedModality::GetCalibration(std::string depth) -{ - return this->GetCalibration(depth, this->GetIdentifierForCurrentProbe()); -} - -mitk::AffineTransform3D::Pointer mitk::USCombinedModality::GetCalibration(std::string depth, std::string probe) +void mitk::USCombinedModality::GenerateData() { - // make sure that there is no '/' which would cause problems for TinyXML - std::replace(probe.begin(), probe.end(), '/', '-'); - - // create identifier for calibration from probe and depth - std::string calibrationKey = probe + mitk::USCombinedModality::ProbeAndDepthSeperator + depth; - - // find calibration for combination of probe identifier and depth - std::map::iterator calibrationIterator - = m_Calibrations.find(calibrationKey); - - if (calibrationIterator == m_Calibrations.end()) { return 0; } + if (m_UltrasoundDevice->GetIsFreezed()) { return; } //if the image is freezed: do nothing - return calibrationIterator->second; -} + //get next image from ultrasound image source + mitk::Image::Pointer image = m_UltrasoundDevice->GetUSImageSource()->GetNextImage(); -void mitk::USCombinedModality::SetCalibration(mitk::AffineTransform3D::Pointer calibration) -{ - if (calibration.IsNull()) + if (image.IsNull() || !image->IsInitialized()) //check the image { - MITK_WARN << "Null pointer passed to SetCalibration of mitk::USDevice. Ignoring call."; + MITK_WARN << "Invalid image in USCombinedModality, aborting!"; return; } + //get output and initialize it if it wasn't initialized before + mitk::Image::Pointer output = this->GetOutput(); + if (!output->IsInitialized()) { output->Initialize(image); } + + //now update image data + mitk::ImageReadAccessor inputReadAccessor(image, image->GetSliceData(0, 0, 0)); + output->SetSlice(inputReadAccessor.GetData()); //copy image data + output->GetGeometry()->SetSpacing(image->GetGeometry()->GetSpacing()); //copy spacing because this might also change + + //and update calibration (= transformation of the image) std::string calibrationKey = this->GetIdentifierForCurrentCalibration(); - if (calibrationKey.empty()) + if (!calibrationKey.empty()) { - MITK_WARN << "Could not get a key for the calibration -> Calibration cannot be set."; - return; + std::map::iterator calibrationIterator + = m_Calibrations.find(calibrationKey); + if (calibrationIterator != m_Calibrations.end()) + { + // transform image according to callibration if one is set + // for current configuration of probe and depth + this->GetOutput()->GetGeometry()->SetIndexToWorldTransform(calibrationIterator->second); + } } - - m_Calibrations[calibrationKey] = calibration; } -bool mitk::USCombinedModality::RemoveCalibration() -{ - return this->RemoveCalibration(this->GetCurrentDepthValue(), this->GetIdentifierForCurrentProbe()); -} -bool mitk::USCombinedModality::RemoveCalibration(std::string depth) +//====================================================================================================================== +/** +bool mitk::USCombinedModality::OnInitialization() +{ +if (m_UltrasoundDevice.IsNull()) { - return this->RemoveCalibration(depth, this->GetIdentifierForCurrentProbe()); +MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; +mitkThrow() << "UltrasoundDevice must not be null."; } -bool mitk::USCombinedModality::RemoveCalibration(std::string depth, std::string probe) +if (m_UltrasoundDevice->GetDeviceState() < mitk::USDevice::State_Initialized) { - // make sure that there is no '/' which would cause problems for TinyXML - std::replace(probe.begin(), probe.end(), '/', '-'); - - // create identifier for calibration from probe and depth - std::string calibrationKey = probe + mitk::USCombinedModality::ProbeAndDepthSeperator + depth; - - return m_Calibrations.erase(calibrationKey) > 0; +return m_UltrasoundDevice->Initialize(); } - -void mitk::USCombinedModality::SetNumberOfSmoothingValues(unsigned int numberOfSmoothingValues) +else { - unsigned int oldNumber = m_NumberOfSmoothingValues; - m_NumberOfSmoothingValues = numberOfSmoothingValues; - - // if filter should be activated or deactivated - if ((oldNumber == 0 && numberOfSmoothingValues != 0) || - (oldNumber != 0 && numberOfSmoothingValues == 0)) - { - this->RebuildFilterPipeline(); - } - m_SmoothingFilter->SetNumerOfValues(numberOfSmoothingValues); +return true; +} } -void mitk::USCombinedModality::SetDelayCount(unsigned int delayCount) +bool mitk::USCombinedModality::OnConnection() { - unsigned int oldCount = m_DelayCount; - m_DelayCount = delayCount; - - // if filter should be activated or deactivated - if ((oldCount == 0 && delayCount != 0) || - (oldCount != 0 && delayCount == 0)) - { - this->RebuildFilterPipeline(); - } - m_DelayFilter->SetDelay(delayCount); +if (m_UltrasoundDevice.IsNull()) +{ +MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; +mitkThrow() << "UltrasoundDevice must not be null."; } -bool mitk::USCombinedModality::OnInitialization() +// connect ultrasound device only if it is not already connected +if (m_UltrasoundDevice->GetDeviceState() >= mitk::USDevice::State_Connected) { - if (m_UltrasoundDevice.IsNull()) - { - MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; - mitkThrow() << "UltrasoundDevice must not be null."; - } - - if (m_UltrasoundDevice->GetDeviceState() < mitk::USDevice::State_Initialized) - { - return m_UltrasoundDevice->Initialize(); - } - else - { - return true; - } +return true; } - -bool mitk::USCombinedModality::OnConnection() +else { - if (m_UltrasoundDevice.IsNull()) - { - MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; - mitkThrow() << "UltrasoundDevice must not be null."; - } - - // connect ultrasound device only if it is not already connected - if (m_UltrasoundDevice->GetDeviceState() >= mitk::USDevice::State_Connected) - { - return true; - } - else - { - return m_UltrasoundDevice->Connect(); - } +return m_UltrasoundDevice->Connect(); +} } bool mitk::USCombinedModality::OnDisconnection() { - if (m_UltrasoundDevice.IsNull()) - { - MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; - mitkThrow() << "UltrasoundDevice must not be null."; - } +if (m_UltrasoundDevice.IsNull()) +{ +MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; +mitkThrow() << "UltrasoundDevice must not be null."; +} - return m_UltrasoundDevice->Disconnect(); +return m_UltrasoundDevice->Disconnect(); } bool mitk::USCombinedModality::OnActivation() { - if (m_UltrasoundDevice.IsNull()) - { - MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; - mitkThrow() << "UltrasoundDevice must not be null."; - } - - mitk::TrackingDeviceSource::Pointer trackingDeviceSource = dynamic_cast(m_TrackingDevice.GetPointer()); - if (trackingDeviceSource.IsNull()) - { - MITK_WARN("USCombinedModality")("USDevice") << "Cannot start tracking as TrackingDeviceSource is null."; - } - trackingDeviceSource->StartTracking(); - - // activate ultrasound device only if it is not already activated - if (m_UltrasoundDevice->GetDeviceState() >= mitk::USDevice::State_Activated) - { - return true; - } - else - { - return m_UltrasoundDevice->Activate(); - } -} - -bool mitk::USCombinedModality::OnDeactivation() +if (m_UltrasoundDevice.IsNull()) { - if (m_UltrasoundDevice.IsNull()) - { - MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; - mitkThrow() << "UltrasoundDevice must not be null."; - } - - mitk::TrackingDeviceSource::Pointer trackingDeviceSource = dynamic_cast(m_TrackingDevice.GetPointer()); - if (trackingDeviceSource.IsNull()) - { - MITK_WARN("USCombinedModality")("USDevice") << "Cannot stop tracking as TrackingDeviceSource is null."; - } - trackingDeviceSource->StopTracking(); - - m_UltrasoundDevice->Deactivate(); - - return m_UltrasoundDevice->GetIsConnected(); +MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; +mitkThrow() << "UltrasoundDevice must not be null."; } -void mitk::USCombinedModality::OnFreeze(bool freeze) +mitk::TrackingDeviceSource::Pointer trackingDeviceSource = dynamic_cast(m_TrackingDevice.GetPointer()); +if (trackingDeviceSource.IsNull()) { - mitk::TrackingDeviceSource::Pointer trackingDeviceSource = dynamic_cast(m_TrackingDevice.GetPointer()); - if (trackingDeviceSource.IsNull()) - { - MITK_WARN("USCombinedModality")("USDevice") << "Cannot freeze tracking."; - } - else - { - if (freeze) { trackingDeviceSource->Freeze(); } - else { trackingDeviceSource->UnFreeze(); } - } - - if (m_UltrasoundDevice.IsNull()) - { - MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; - mitkThrow() << "UltrasoundDevice must not be null."; - } - m_UltrasoundDevice->SetIsFreezed(freeze); +MITK_WARN("USCombinedModality")("USDevice") << "Cannot start tracking as TrackingDeviceSource is null."; } +trackingDeviceSource->StartTracking(); -mitk::NavigationDataSource::Pointer mitk::USCombinedModality::GetNavigationDataSource() +// activate ultrasound device only if it is not already activated +if (m_UltrasoundDevice->GetDeviceState() >= mitk::USDevice::State_Activated) { - return m_LastFilter.GetPointer(); +return true; } - -bool mitk::USCombinedModality::GetIsCalibratedForCurrentStatus() +else { - return m_Calibrations.find(this->GetIdentifierForCurrentCalibration()) != m_Calibrations.end(); +return m_UltrasoundDevice->Activate(); } - -bool mitk::USCombinedModality::GetContainsAtLeastOneCalibration() -{ - return !m_Calibrations.empty(); } -void mitk::USCombinedModality::GenerateData() +bool mitk::USCombinedModality::OnDeactivation() { - if (m_UltrasoundDevice->GetIsFreezed()) { return; } //if the image is freezed: do nothing - - //get next image from ultrasound image source - mitk::Image::Pointer image = m_UltrasoundDevice->GetUSImageSource()->GetNextImage(); - - if (image.IsNull() || !image->IsInitialized()) //check the image - { - MITK_WARN << "Invalid image in USCombinedModality, aborting!"; - return; - } - - //get output and initialize it if it wasn't initialized before - mitk::Image::Pointer output = this->GetOutput(); - if (!output->IsInitialized()) { output->Initialize(image); } - - //now update image data - mitk::ImageReadAccessor inputReadAccessor(image, image->GetSliceData(0, 0, 0)); - output->SetSlice(inputReadAccessor.GetData()); //copy image data - output->GetGeometry()->SetSpacing(image->GetGeometry()->GetSpacing()); //copy spacing because this might also change - - //and update calibration (= transformation of the image) - std::string calibrationKey = this->GetIdentifierForCurrentCalibration(); - if (!calibrationKey.empty()) - { - std::map::iterator calibrationIterator - = m_Calibrations.find(calibrationKey); - if (calibrationIterator != m_Calibrations.end()) - { - // transform image according to callibration if one is set - // for current configuration of probe and depth - this->GetOutput()->GetGeometry()->SetIndexToWorldTransform(calibrationIterator->second); - } - } +if (m_UltrasoundDevice.IsNull()) +{ +MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; +mitkThrow() << "UltrasoundDevice must not be null."; } -std::string mitk::USCombinedModality::SerializeCalibration() +mitk::TrackingDeviceSource::Pointer trackingDeviceSource = dynamic_cast(m_TrackingDevice.GetPointer()); +if (trackingDeviceSource.IsNull()) { - std::stringstream result; - result << "" << std::endl; - // For each calibration in the set - for (std::map::iterator it = m_Calibrations.begin(); it != m_Calibrations.end(); it++) - { - mitk::AffineTransform3D::MatrixType matrix = it->second->GetMatrix(); - mitk::AffineTransform3D::TranslationType translation = it->second->GetTranslation(); - TiXmlElement elem(it->first); - // Serialize Matrix - elem.SetDoubleAttribute("M00", matrix[0][0]); - elem.SetDoubleAttribute("M01", matrix[0][1]); - elem.SetDoubleAttribute("M02", matrix[0][2]); - elem.SetDoubleAttribute("M10", matrix[1][0]); - elem.SetDoubleAttribute("M11", matrix[1][1]); - elem.SetDoubleAttribute("M12", matrix[1][2]); - elem.SetDoubleAttribute("M20", matrix[2][0]); - elem.SetDoubleAttribute("M21", matrix[2][1]); - elem.SetDoubleAttribute("M22", matrix[2][2]); - // Serialize Offset - elem.SetDoubleAttribute("T0", translation[0]); - elem.SetDoubleAttribute("T1", translation[1]); - elem.SetDoubleAttribute("T2", translation[2]); - - result << elem << std::endl; - } - result << "" << std::endl; - - return result.str(); +MITK_WARN("USCombinedModality")("USDevice") << "Cannot stop tracking as TrackingDeviceSource is null."; } +trackingDeviceSource->StopTracking(); -void mitk::USCombinedModality::DeserializeCalibration(const std::string& xmlString, bool clearPreviousCalibrations) -{ - // Sanitize Input - if (xmlString == "") - { - MITK_ERROR << "Empty string passed to Deserialize() method of CombinedModality. Aborting..."; - mitkThrow() << "Empty string passed to Deserialize() method of CombinedModality. Aborting..."; - return; - } - // Clear previous calibrations if necessary - if (clearPreviousCalibrations) m_Calibrations.clear(); +m_UltrasoundDevice->Deactivate(); - // Parse Input - TiXmlDocument doc; - if (!doc.Parse(xmlString.c_str())) - { - MITK_ERROR << "Unable to deserialize calibrations in CombinedModality. Error was: " << doc.ErrorDesc(); - mitkThrow() << "Unable to deserialize calibrations in CombinedModality. Error was: " << doc.ErrorDesc(); - return; - } - TiXmlElement* root = doc.FirstChildElement(); - if (root == nullptr) - { - MITK_ERROR << "Unable to deserialize calibrations in CombinedModality. String contained no root element."; - mitkThrow() << "Unable to deserialize calibrations in CombinedModality. String contained no root element."; - return; - } - // Read Calibrations - for (TiXmlElement* elem = root->FirstChildElement(); elem != nullptr; elem = elem->NextSiblingElement()) - { - mitk::AffineTransform3D::MatrixType matrix; - mitk::AffineTransform3D::OffsetType translation; - - std::string calibName = elem->Value(); - - // Deserialize Matrix - elem->QueryDoubleAttribute("M00", &matrix[0][0]); - elem->QueryDoubleAttribute("M01", &matrix[0][1]); - elem->QueryDoubleAttribute("M02", &matrix[0][2]); - elem->QueryDoubleAttribute("M10", &matrix[1][0]); - elem->QueryDoubleAttribute("M11", &matrix[1][1]); - elem->QueryDoubleAttribute("M12", &matrix[1][2]); - elem->QueryDoubleAttribute("M20", &matrix[2][0]); - elem->QueryDoubleAttribute("M21", &matrix[2][1]); - elem->QueryDoubleAttribute("M22", &matrix[2][2]); - - // Deserialize Offset - elem->QueryDoubleAttribute("T0", &translation[0]); - elem->QueryDoubleAttribute("T1", &translation[1]); - elem->QueryDoubleAttribute("T2", &translation[2]); - - mitk::AffineTransform3D::Pointer calibration = mitk::AffineTransform3D::New(); - calibration->SetMatrix(matrix); - calibration->SetTranslation(translation); - m_Calibrations[calibName] = calibration; - } +return m_UltrasoundDevice->GetIsConnected(); } -std::string mitk::USCombinedModality::GetIdentifierForCurrentCalibration() +void mitk::USCombinedModality::OnFreeze(bool freeze) { - return this->GetIdentifierForCurrentProbe() - + mitk::USCombinedModality::ProbeAndDepthSeperator - + this->GetCurrentDepthValue(); -} - -std::string mitk::USCombinedModality::GetIdentifierForCurrentProbe() +mitk::TrackingDeviceSource::Pointer trackingDeviceSource = dynamic_cast(m_TrackingDevice.GetPointer()); +if (trackingDeviceSource.IsNull()) { - us::ServiceProperties usdeviceProperties = m_UltrasoundDevice->GetServiceProperties(); - - us::ServiceProperties::const_iterator probeIt = usdeviceProperties.find( - mitk::USCombinedModality::GetPropertyKeys().US_PROPKEY_PROBES_SELECTED); - - // get probe identifier from control interface for probes - std::string probeName = mitk::USCombinedModality::DefaultProbeIdentifier; - if (probeIt != usdeviceProperties.end()) - { - probeName = (probeIt->second).ToString(); - } - - // make sure that there is no '/' which would cause problems for TinyXML - std::replace(probeName.begin(), probeName.end(), '/', '-'); - - return probeName; +MITK_WARN("USCombinedModality")("USDevice") << "Cannot freeze tracking."; } - -std::string mitk::USCombinedModality::GetCurrentDepthValue() +else { - us::ServiceProperties usdeviceProperties = m_UltrasoundDevice->GetServiceProperties(); - - // get string for depth value from the micro service properties - std::string depth; - us::ServiceProperties::iterator depthIterator = usdeviceProperties.find( - mitk::USCombinedModality::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH); - - if (depthIterator != usdeviceProperties.end()) - { - depth = depthIterator->second.ToString(); - } - else - { - depth = "0"; - } - - return depth; +if (freeze) { trackingDeviceSource->Freeze(); } +else { trackingDeviceSource->UnFreeze(); } } -void mitk::USCombinedModality::RebuildFilterPipeline() +if (m_UltrasoundDevice.IsNull()) { - m_LastFilter = m_TrackingDevice; - - if (m_NumberOfSmoothingValues > 0) - { - for (unsigned int i = 0; i < m_TrackingDevice->GetNumberOfOutputs(); i++) - { - m_SmoothingFilter->SetInput(i, m_LastFilter->GetOutput(i)); - } - m_LastFilter = m_SmoothingFilter; - } - - if (m_DelayCount > 0) - { - for (unsigned int i = 0; i < m_TrackingDevice->GetNumberOfOutputs(); i++) - { - m_DelayFilter->SetInput(i, m_LastFilter->GetOutput(i)); - } - m_LastFilter = m_DelayFilter; - } +MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; +mitkThrow() << "UltrasoundDevice must not be null."; } - -void mitk::USCombinedModality::RegisterAsMicroservice() -{ - //Get Context - us::ModuleContext* context = us::GetModuleContext(); - - //Define ServiceProps - us::ServiceProperties props; - mitk::UIDGenerator uidGen = - mitk::UIDGenerator("org.mitk.services.USCombinedModality", 16); - props[US_PROPKEY_ID] = uidGen.GetUID(); - props[US_PROPKEY_DEVICENAME] = this->GetName(); - props[US_PROPKEY_CLASS] = this->GetDeviceClass(); - - m_ServiceProperties = props; - - m_ServiceRegistration = context->RegisterService(this, props); +m_UltrasoundDevice->SetIsFreezed(freeze); } +*/ diff --git a/Modules/US/USNavigation/mitkUSCombinedModality.h b/Modules/US/USNavigation/mitkUSCombinedModality.h index dea4bc126d..cb146a6216 100644 --- a/Modules/US/USNavigation/mitkUSCombinedModality.h +++ b/Modules/US/USNavigation/mitkUSCombinedModality.h @@ -1,270 +1,124 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKUSCombinedModality_H_HEADER_INCLUDED_ #define MITKUSCombinedModality_H_HEADER_INCLUDED_ #include #include "mitkUSDevice.h" +#include "mitkImageSource.h" +#include "mitkAbstractUltrasoundTrackerDevice.h" #include "mitkNavigationDataSource.h" // Microservices #include #include namespace itk { template class SmartPointer; } namespace mitk { - class NavigationDataSmoothingFilter; - class NavigationDataDelayFilter; class USControlInterfaceBMode; class USControlInterfaceProbes; class USControlInterfaceDoppler; /** * \brief Combination of USDevice and NavigationDataSource. - * This class can be used as any USDevice subclass. Additionally tracking data be + * This class can be used as an ImageSource subclass. Additionally tracking data be * retrieved from the NavigationDataSource returned by GetTrackingDevice(). * * A calibration of the ultrasound image stream to the navigation datas can be set * for the currently active zoom level (of the ultrasound device) by SetCalibration(). * The ultrasound images are transformed according to this calibration in the * GenerateData() method. */ - class MITKUSNAVIGATION_EXPORT USCombinedModality : public USDevice + class MITKUSNAVIGATION_EXPORT USCombinedModality : public mitk::AbstractUltrasoundTrackerDevice { public: - static const std::string DeviceClassIdentifier; - static const char* DefaultProbeIdentifier; - static const char* ProbeAndDepthSeperator; - mitkClassMacro(USCombinedModality, USDevice); - mitkNewMacro4Param(USCombinedModality, USDevice::Pointer, itk::SmartPointer, std::string, std::string); + mitkClassMacro(USCombinedModality, mitk::AbstractUltrasoundTrackerDevice); + mitkNewMacro3Param(USCombinedModality, USDevice::Pointer, itk::SmartPointer, bool); - itkGetMacro(UltrasoundDevice, itk::SmartPointer); - itkSetMacro(UltrasoundDevice, itk::SmartPointer); - itkGetMacro(TrackingDevice, itk::SmartPointer); - itkSetMacro(TrackingDevice, itk::SmartPointer); - - /** - * \brief Getter for calibration data of the currently active depth and probe. - * - * \return Transformation for calibration or null if no calibration is available. - */ - AffineTransform3D::Pointer GetCalibration(); - - /** - * \brief Getter for calibration data of the given depth and the currently active probe. - * - * \param depth depth of the b mode ultrasound image for which the calibration should be returned - * \return Transformation for calibration or null if no calibration is available. - */ - AffineTransform3D::Pointer GetCalibration(std::string depth); - - /** - * \brief Getter for calibration data of the given depth and probe. - * - * \param depth depth of the b mode ultrasound image for which the calibration should be returned - * \param probe probe of the ultrasound device for which the calibration should be returned - * \return Transformation for calibration or null if no calibration is available. - */ - AffineTransform3D::Pointer GetCalibration(std::string depth, std::string probe); - - /** - * \brief Sets a transformation as calibration data. - * Calibration data is set for the currently activated probe and their current - * zoom factor. It also marks the device as calibrated. - */ - void SetCalibration(AffineTransform3D::Pointer calibration); - - /** - * \brief Removes the calibration data of the currently active depth and probe. - * \return true on success, false if there was no calibration - */ - bool RemoveCalibration(); - - /** - * \brief Removes the calibration data of the given depth and the currently active probe. - * - * \param depth depth of the b mode ultrasound image for which the calibration should be removed - * \return true on success, false if there was no calibration - */ - bool RemoveCalibration(std::string depth); - - /** - * \brief Removes the calibration data of the given depth and probe. - * - * \param depth depth of the b mode ultrasound image for which the calibration should be removed - * \param probe probe of the ultrasound device for which the calibration should be removed - * \return true on success, false if there was no calibration - */ - bool RemoveCalibration(std::string depth, std::string probe); - - /** - * \brief Returns the Class of the Device. - */ - virtual std::string GetDeviceClass() override; - - /** - * \brief Wrapper for returning USImageSource of the UltrasoundDevice. - */ - virtual USImageSource::Pointer GetUSImageSource() override; /** * \brief Wrapper for returning custom control interface of the UltrasoundDevice. */ virtual itk::SmartPointer GetControlInterfaceCustom() override; /** * \brief Wrapper for returning B mode control interface of the UltrasoundDevice. */ virtual itk::SmartPointer GetControlInterfaceBMode() override; /** * \brief Wrapper for returning probes control interface of the UltrasoundDevice. */ virtual itk::SmartPointer GetControlInterfaceProbes() override; /** * \brief Wrapper for returning doppler control interface of the UltrasoundDevice. */ virtual itk::SmartPointer GetControlInterfaceDoppler() override; - virtual itk::SmartPointer GetNavigationDataSource(); - - /** - * \return true if the device is calibrated for the currently selected probe with the current zoom level - */ - bool GetIsCalibratedForCurrentStatus(); - - /** - * \return true if a calibration was loaded for at least one probe and depth - */ - bool GetContainsAtLeastOneCalibration(); - - /** - * \brief Remove this device from the micro service. - * This method is public for mitk::USCombinedModality, because this devices - * can be completly removed. This is not possible for API devices, which - * should be available while their sub module is loaded. - */ - void UnregisterOnService(); - - /** - * \brief Serializes all contained calibrations into an xml fragment. - * - * The returned string contains one parent node named "calibrations" and several - * subnodes, one for each calibration that is present. - */ - std::string SerializeCalibration(); - - /** - * \brief Deserializes a string provided by a prior call to Serialize(). - * If the bool flag is true, all prior calibrations will be deleted. - * If the flag is set to false, prior calibrations will be retained, but overwritten - * if one of equal name is present. - * - * \throws mitk::Exception if the given string could not be parsed correctly. - */ - void DeserializeCalibration(const std::string &xmlString, bool clearPreviousCalibrations = true); - - void SetNumberOfSmoothingValues(unsigned int numberOfSmoothingValues); - - void SetDelayCount(unsigned int delayCount); - - void RegisterAsMicroservice(); - - /** - *\brief These Constants are used in conjunction with Microservices - */ - static const std::string US_INTERFACE_NAME; - static const std::string US_PROPKEY_DEVICENAME; - static const std::string US_PROPKEY_CLASS; - static const std::string US_PROPKEY_ID; protected: - USCombinedModality(USDevice::Pointer usDevice, itk::SmartPointer trackingDevice, std::string manufacturer = "", std::string model = ""); + USCombinedModality( USDevice::Pointer usDevice, + itk::SmartPointer trackingDevice, + bool trackedUltrasoundActive = false ); virtual ~USCombinedModality(); /** * \brief Initializes UltrasoundDevice. */ - virtual bool OnInitialization() override; + //___virtual bool OnInitialization(); /** * \brief Connects UltrasoundDevice. */ - virtual bool OnConnection() override; + //___virtual bool OnConnection(); /** * \brief Disconnects UltrasoundDevice. */ - virtual bool OnDisconnection() override; + //___virtual bool OnDisconnection(); /** * \brief Activates UltrasoundDevice. */ - virtual bool OnActivation() override; + //___virtual bool OnActivation(); /** * \brief Deactivates UltrasoundDevice. */ - virtual bool OnDeactivation() override; + //___ virtual bool OnDeactivation(); /** * \brief Freezes or unfreezes UltrasoundDevice. */ - virtual void OnFreeze(bool) override; + //___virtual void OnFreeze(bool); + + // void RegisterAsMicroservice() override; /** * \brief Grabs the next frame from the input. * This method is called internally, whenever Update() is invoked by an Output. */ void GenerateData() override; - std::string GetIdentifierForCurrentCalibration(); - std::string GetIdentifierForCurrentProbe(); - std::string GetCurrentDepthValue(); - - void RebuildFilterPipeline(); - - USDevice::Pointer m_UltrasoundDevice; - itk::SmartPointer m_TrackingDevice; - std::map m_Calibrations; - - itk::SmartPointer m_SmoothingFilter; - itk::SmartPointer m_DelayFilter; - itk::SmartPointer m_LastFilter; - - unsigned int m_NumberOfSmoothingValues; - unsigned int m_DelayCount; - - private: - /** - * \brief The device's ServiceRegistration object that allows to modify it's Microservice registraton details. - */ - us::ServiceRegistration m_ServiceRegistration; - - /** - * \brief Properties of the device's Microservice. - */ - us::ServiceProperties m_ServiceProperties; }; } // namespace mitk -MITK_DECLARE_SERVICE_INTERFACE(mitk::USCombinedModality, "org.mitk.services.USCombinedModality") #endif // MITKUSCombinedModality_H_HEADER_INCLUDED_ diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/IO/mitkUSNavigationCombinedModalityPersistence.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/IO/mitkUSNavigationCombinedModalityPersistence.cpp index cd2a4d0017..44f8bad907 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/IO/mitkUSNavigationCombinedModalityPersistence.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/IO/mitkUSNavigationCombinedModalityPersistence.cpp @@ -1,213 +1,213 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkUSNavigationCombinedModalityPersistence.h" #include "mitkUSCombinedModality.h" // Microservices #include #include #include #include // Qt #include #include #include #include #include "internal/org_mbi_gui_qt_usnavigation_Activator.h" mitk::USNavigationCombinedModalityPersistence::USNavigationCombinedModalityPersistence() { us::ModuleContext* context = us::GetModuleContext(); this->LoadStoredDevices(); // to be notified about every register and unregister of an USDevice std::string filterExcludeCombinedModalities = "(&(" + us::ServiceConstants::OBJECTCLASS() + "=" + "org.mitk.services.UltrasoundDevice)(!(" + mitk::USDevice::GetPropertyKeys().US_PROPKEY_CLASS + "=" + mitk::USCombinedModality::DeviceClassIdentifier + ")))"; context->AddServiceListener(this, &mitk::USNavigationCombinedModalityPersistence::OnServiceEvent, filterExcludeCombinedModalities); // to be notified about every register and unregister of an NavigationDataSource context->AddServiceListener(this, &mitk::USNavigationCombinedModalityPersistence::OnServiceEvent, "(" + us::ServiceConstants::OBJECTCLASS() + "=" + us_service_interface_iid() + ")"); } mitk::USNavigationCombinedModalityPersistence::~USNavigationCombinedModalityPersistence() { //this->StoreCurrentDevices(); //disabled because persistence is buggy } void mitk::USNavigationCombinedModalityPersistence::OnServiceEvent(const us::ServiceEvent event) { if ( event.GetType() == event.REGISTERED ) { //this->LoadStoredDevices(); //disabled because persistence is buggy } } void mitk::USNavigationCombinedModalityPersistence::StoreCurrentDevices() { QList devices; us::ModuleContext* context = us::GetModuleContext(); // get all combined modality from the service registry std::string filterOnlyCombinedModalities = "(&(" + us::ServiceConstants::OBJECTCLASS() + "=" + "org.mitk.services.UltrasoundDevice)(" + mitk::USDevice::GetPropertyKeys().US_PROPKEY_CLASS + "=" + mitk::USCombinedModality::DeviceClassIdentifier + "))"; std::vector > services = context->GetServiceReferences(filterOnlyCombinedModalities); for ( std::vector >::iterator it = services.begin(); it != services.end(); ++it ) { QStringList deviceStrings; mitk::USCombinedModality::Pointer currentDevice = dynamic_cast(context->GetService(*it)); if ( currentDevice.IsNotNull() ) { // save manufacturer and model strig of the combined modality - deviceStrings.push_back(QString::fromStdString(currentDevice->GetManufacturer())); - deviceStrings.push_back(QString::fromStdString(currentDevice->GetName())); + deviceStrings.push_back(QString::fromStdString(currentDevice->GetUltrasoundDevice()->GetManufacturer())); + deviceStrings.push_back(QString::fromStdString(currentDevice->GetUltrasoundDevice()->GetName())); // save name of the navigation data source mitk::NavigationDataSource::Pointer navigationDataSource = currentDevice->GetNavigationDataSource(); if ( currentDevice.IsNull() ) { continue; } deviceStrings.push_back(QString::fromStdString(navigationDataSource->GetName())); // save manufacturer, model and comment of the ultrasound device mitk::USDevice::Pointer ultrasoundDevice = currentDevice->GetUltrasoundDevice(); if ( ultrasoundDevice.IsNull() ) { continue; } deviceStrings.push_back(QString::fromStdString(ultrasoundDevice->GetManufacturer())); deviceStrings.push_back(QString::fromStdString(ultrasoundDevice->GetName())); deviceStrings.push_back(QString::fromStdString(ultrasoundDevice->GetComment())); // save calibration of the combined modality deviceStrings.push_back(QString::fromStdString(currentDevice->SerializeCalibration())); } devices.push_back(deviceStrings); } // store everything in QSettings QSettings settings; settings.setValue("combined-modalities", devices); } void mitk::USNavigationCombinedModalityPersistence::LoadStoredDevices() { // load everything from QSettings QSettings settings; QList devices = settings.value("combined-modalities").value< QList >(); for ( QList::iterator it = devices.begin(); it != devices.end(); ++it ) { // get the saved strings for the combined modality (there must be at least // the seven strings, which where saved before) QStringList stringList = it->toStringList(); // test if the combined modality wasn't restored before if (stringList.size() >= 7 && this->GetCombinedModality(stringList.at(0).toStdString(), stringList.at(1).toStdString()).IsNull()) { // try to get matching navigation data source and ultrasound device mitk::NavigationDataSource::Pointer navigationDataSource = this->GetNavigationDataSource(stringList.at(2).toStdString()); mitk::USDevice::Pointer usDevice = this->GetUSDevice(stringList.at(3).toStdString(), stringList.at(4).toStdString(), stringList.at(5).toStdString()); // create the combined modality if matching navigation data source and // ultrasound device werde found if ( navigationDataSource.IsNotNull() && usDevice.IsNotNull() ) { - mitk::USCombinedModality::Pointer combinedModality = mitk::USCombinedModality::New(usDevice, navigationDataSource, stringList.at(0).toStdString(), stringList.at(1).toStdString()); + mitk::USCombinedModality::Pointer combinedModality = mitk::USCombinedModality::New(usDevice, navigationDataSource, false); combinedModality->DeserializeCalibration(stringList.at(6).toStdString()); - combinedModality->Initialize(); + combinedModality->GetUltrasoundDevice()->Initialize(); } } } } mitk::USCombinedModality::Pointer mitk::USNavigationCombinedModalityPersistence::GetCombinedModality(std::string manufacturer, std::string model) { us::ModuleContext* context = us::GetModuleContext(); std::string filterOnlyCombinedModalities = "(&(" + us::ServiceConstants::OBJECTCLASS() + "=" + "org.mitk.services.UltrasoundDevice)(" + mitk::USDevice::GetPropertyKeys().US_PROPKEY_CLASS + "=" + mitk::USCombinedModality::DeviceClassIdentifier + "))"; std::vector > services = context->GetServiceReferences(filterOnlyCombinedModalities); for ( std::vector >::iterator it = services.begin(); it != services.end(); ++it ) { mitk::USCombinedModality::Pointer currentDevice = dynamic_cast(context->GetService(*it)); if ( currentDevice.IsNotNull() ) { - if ( currentDevice->GetManufacturer() == manufacturer && currentDevice->GetName() == model ) + if ( currentDevice->GetUltrasoundDevice()->GetManufacturer() == manufacturer && currentDevice->GetUltrasoundDevice()->GetName() == model ) { return currentDevice; } } } return 0; } mitk::USDevice::Pointer mitk::USNavigationCombinedModalityPersistence::GetUSDevice(std::string manufacturer, std::string model, std::string comment) { us::ModuleContext* context = us::GetModuleContext(); std::string filterExcludeCombinedModalities = "(&(" + us::ServiceConstants::OBJECTCLASS() + "=" + "org.mitk.services.UltrasoundDevice)(!(" + mitk::USDevice::GetPropertyKeys().US_PROPKEY_CLASS + "=" + mitk::USCombinedModality::DeviceClassIdentifier + ")))"; std::vector > services = context->GetServiceReferences(filterExcludeCombinedModalities); for ( std::vector >::iterator it = services.begin(); it != services.end(); ++it ) { mitk::USDevice::Pointer currentDevice = dynamic_cast(context->GetService(*it)); if ( currentDevice.IsNotNull() ) { if ( currentDevice->GetManufacturer() == manufacturer && currentDevice->GetName() == model && currentDevice->GetComment() == comment ) { return currentDevice; } } } return 0; } mitk::NavigationDataSource::Pointer mitk::USNavigationCombinedModalityPersistence::GetNavigationDataSource(std::string name) { us::ModuleContext* context = us::GetModuleContext(); std::vector > services = context->GetServiceReferences(); for ( std::vector >::iterator it = services.begin(); it != services.end(); ++it ) { mitk::NavigationDataSource::Pointer currentDevice = dynamic_cast(context->GetService(*it)); if ( currentDevice.IsNotNull() ) { if ( currentDevice->GetName() == name ) { return currentDevice; } } } return 0; } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSAbstractNavigationStep.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSAbstractNavigationStep.cpp index 774f3a2594..e7afbbd4bf 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSAbstractNavigationStep.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSAbstractNavigationStep.cpp @@ -1,208 +1,209 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkUSAbstractNavigationStep.h" #include "ui_QmitkUSAbstractNavigationStep.h" #include "mitkNavigationDataToNavigationDataFilter.h" const char* QmitkUSAbstractNavigationStep::DATANAME_SETTINGS = "Settings"; const char* QmitkUSAbstractNavigationStep::DATANAME_IMAGESTREAM = "US Image Stream"; const char* QmitkUSAbstractNavigationStep::DATANAME_BASENODE = QmitkUSAbstractNavigationStep::DATANAME_IMAGESTREAM; QmitkUSAbstractNavigationStep::QmitkUSAbstractNavigationStep(QWidget *parent) : QWidget(parent), m_NavigationStepState(State_Stopped) { } QmitkUSAbstractNavigationStep::~QmitkUSAbstractNavigationStep() { } bool QmitkUSAbstractNavigationStep::OnRestartStep() { return this->OnStopStep() && this->OnStartStep(); } bool QmitkUSAbstractNavigationStep::GetIsRestartable() { return true; } QmitkUSAbstractNavigationStep::FilterVector QmitkUSAbstractNavigationStep::GetFilter() { return FilterVector(); } void QmitkUSAbstractNavigationStep::SetDataStorage(itk::SmartPointer dataStorage) { m_DataStorage = dataStorage; } -void QmitkUSAbstractNavigationStep::SetCombinedModality(itk::SmartPointer combinedModality) +void QmitkUSAbstractNavigationStep::SetCombinedModality(itk::SmartPointer combinedModality) { m_CombinedModality = combinedModality; + MITK_INFO << "Combined modality set to NULL: " << m_CombinedModality.IsNull(); this->OnSetCombinedModality(); } bool QmitkUSAbstractNavigationStep::StartStep() { if ( this->GetNavigationStepState() == State_Stopped && this->OnStartStep() ) { m_NavigationStepState = State_Started; return true; } return false; } bool QmitkUSAbstractNavigationStep::StopStep() { if ( this->GetNavigationStepState() == State_Started || ( this->GetNavigationStepState() > State_Started && this->DeactivateStep() ) ) { if ( this->OnStopStep() ) { m_NavigationStepState = State_Stopped; return true; } } return false; } bool QmitkUSAbstractNavigationStep::RestartStep() { return this->OnRestartStep(); } bool QmitkUSAbstractNavigationStep::FinishStep() { if ( this->GetNavigationStepState() > State_Started && this->DeactivateStep() ) { if ( this->OnFinishStep() ) { m_NavigationStepState = State_Started; return true; } } return false; } bool QmitkUSAbstractNavigationStep::ActivateStep() { if ( this->GetNavigationStepState() == State_Started || ( this->GetNavigationStepState() < State_Started && this->StartStep() ) ) { if ( this->OnActivateStep() ) { m_NavigationStepState = State_Active; return true; } } return false; } bool QmitkUSAbstractNavigationStep::DeactivateStep() { if ( this->GetNavigationStepState() == State_Active ) { if ( this->OnDeactivateStep() ) { m_NavigationStepState = State_Started; return true; } } return false; } void QmitkUSAbstractNavigationStep::Update() { this->OnUpdate(); } QmitkUSAbstractNavigationStep::NavigationStepState QmitkUSAbstractNavigationStep::GetNavigationStepState() { return m_NavigationStepState; } itk::SmartPointer QmitkUSAbstractNavigationStep::GetDataStorage(bool throwNull) { if ( throwNull && m_DataStorage.IsNull() ) { MITK_ERROR << "Data storage must be set to step widget before."; mitkThrow() << "Data storage must be set to step widget before."; } return m_DataStorage; } -itk::SmartPointer QmitkUSAbstractNavigationStep::GetCombinedModality(bool throwNull) +itk::SmartPointer QmitkUSAbstractNavigationStep::GetCombinedModality(bool throwNull) { if ( throwNull && m_CombinedModality.IsNull() ) { - MITK_ERROR << "Combined modality is not set yet for this widget."; + MITK_INFO << "Combined modality is not set yet for this widget."; mitkThrow() << "Combined modality is not set yet for this widget."; } return m_CombinedModality; } itk::SmartPointer QmitkUSAbstractNavigationStep::GetNamedDerivedNode(const char *name, const char *sourceName) { if ( m_DataStorage.IsNull() ) { MITK_ERROR << "Data storage must be set to step widget before."; mitkThrow() << "Data storage must be set to step widget before."; } mitk::DataNode::Pointer sourceNode = m_DataStorage->GetNamedNode(sourceName); if ( sourceNode.IsNull() ) { MITK_WARN << "Source node cannot be found in data storage. Returning null."; return nullptr; } return m_DataStorage->GetNamedDerivedNode(name, m_DataStorage->GetNamedNode(sourceName)); } itk::SmartPointer QmitkUSAbstractNavigationStep::GetNamedDerivedNodeAndCreate(const char* name, const char* sourceName) { if ( m_DataStorage.IsNull() ) { MITK_ERROR << "Data storage must be set to step widget before."; mitkThrow() << "Data storage must be set to step widget before."; } mitk::DataNode::Pointer sourceNode = m_DataStorage->GetNamedNode(sourceName); mitk::DataNode::Pointer dataNode = m_DataStorage->GetNamedDerivedNode(name, sourceNode); if ( dataNode.IsNull() ) { dataNode = mitk::DataNode::New(); dataNode->SetName(name); if ( sourceNode.IsNotNull() ) {this->GetDataStorage()->Add(dataNode, sourceNode);} else {this->GetDataStorage()->Add(dataNode);} } return dataNode; } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSAbstractNavigationStep.h b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSAbstractNavigationStep.h index f61a605670..02d663a7c9 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSAbstractNavigationStep.h +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSAbstractNavigationStep.h @@ -1,311 +1,311 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKUSABSTRACTNAVIGATIONSTEP_H #define QMITKUSABSTRACTNAVIGATIONSTEP_H #include #include "mitkDataStorage.h" -#include "mitkUSCombinedModality.h" +#include "mitkAbstractUltrasoundTrackerDevice.h" namespace itk { template class SmartPointer; } namespace mitk { class NavigationDataToNavigationDataFilter; } /** * \brief Abstract base class for navigation step widgets. * * This class defines a life cycle for navigation steps. Steps can be activated * and deactivated. The first time a step is activated, it is started before * the activation. Steps can be stopped, finished and restarted, too. * * On every state change, the corresponding virtual On... method is called * (OnStartStep(), OnActivateStep(), OnFinishStep(), ...). These methods are * to implement by concrete navigation step widgets. While a step is in the * "active" state, its OnUpdate() method is called periodically. */ class QmitkUSAbstractNavigationStep : public QWidget { Q_OBJECT signals: /** * \brief Signals that all necessary actions where done. * The user can proceed with the next stept after this was signaled. */ void SignalReadyForNextStep(); /** * \brief Signals that it is no longer possible to proceed with following steps. * This signal is emmited when the result data of the step was removed or * changed, so that the old results are invalid for following steps. */ void SignalNoLongerReadyForNextStep(); /** * \brief Signals that the combined modality was changed by this step. * This signal is mainly for steps which creates the combined modality. The * new combined modality is given as a parameter. */ - void SignalCombinedModalityChanged(itk::SmartPointer); + void SignalCombinedModalityChanged(itk::SmartPointer); /** * \brief Signals that an intermediate result was produced. * The properties of the given data node must contain the results. This signal * can be used to log the intermediate results of an experiment, for example * by using the mitk::USNavigationExperimentLogging. */ void SignalIntermediateResult(const itk::SmartPointer); /** * \brief Signals that the settings node was changed. * This signal must not be emited in an OnSettingsChanged() method. */ void SignalSettingsNodeChanged(itk::SmartPointer); public: typedef std::vector< itk::SmartPointer > FilterVector; enum NavigationStepState { State_Stopped, State_Started, State_Active }; static const char* DATANAME_SETTINGS; static const char* DATANAME_IMAGESTREAM; static const char* DATANAME_BASENODE; explicit QmitkUSAbstractNavigationStep(QWidget *parent = 0); ~QmitkUSAbstractNavigationStep(); /** * \brief Getter for the title of the navigation step. * This title should be human readable and can be used to display the * available steps and the currently active step to the user. * The method has to be implemented by a concrete subclass. */ virtual QString GetTitle() = 0; /** * \brief Indicates if it makes sense to be able to restart the step. * This method must be implemented by concrete subclasses if it should not be * possible to restart them. * * \return true for the default implementation */ virtual bool GetIsRestartable(); /** * \brief Called every time the settings for the navigation process where changed. * This method may be implemented by a concrete subclass. The default * implementation does nothing. */ virtual void OnSettingsChanged(const itk::SmartPointer /*settingsNode*/) { } /** * \brief Getter for navigation data filters of the navigation step. * This method may be implemented by a concrete subclass. The default * implementation returns an empty vector. * * \return all navigation data filters that should be updated during the navigation process */ virtual FilterVector GetFilter(); /** * \brief Sets the data storage for the exchange of results between navigation steps. */ void SetDataStorage(itk::SmartPointer dataStorage); /** * \brief Sets the combined modality for the navigation step. * OnSetCombinedModality() is called internal. */ - void SetCombinedModality(itk::SmartPointer combinedModality); + void SetCombinedModality(itk::SmartPointer combinedModality); /** * \brief Should be called to start the navigation step. * \return true if the state was 'stopped' before and OnStartStep() returns true */ bool StartStep(); /** * \brief Should be called to stop the navigation step. * \return true if the state was 'started' (or 'active') and OnStopStep() (and OnDeactivateStep()) return true */ bool StopStep(); /** * \brief Should be called to restart the navigation step. * \return true if OnRestartStep() returns true */ bool RestartStep(); /** * \brief Should be called to finish the navigation step. * The state has to be 'active' before and is 'started' afterwards. * * \return true if the state was 'active' and DeactivateStep() and OnFinishStep() return true */ bool FinishStep(); /** * \brief Should be called to activate the navigation step. * The step gets started before if it was stopped. * * \return true if the state wasn't 'activated' and OnActivateStep() returns true */ bool ActivateStep(); /** * \brief Should be called to deactivate the navigation step. * \return true if the state was 'activated' and OnDeactivateStep() returns true */ bool DeactivateStep(); /** * \brief Should be called periodically while the navigation step is active. * Internal, the method OnUpdate() is called. */ void Update(); /** * \brief Get the current state of the navigation step. * \return State_Stopped, State_Started or State_Active */ NavigationStepState GetNavigationStepState(); protected: /** * \brief Called when the navigation step gets started. * This method has to be implemented by a concrete subclass to handle actions * necessary for starting the step (e.g. initializing that has only to be done * once). * * \return if the actions were done successfully */ virtual bool OnStartStep() = 0; /** * \brief Callen when the navigation step gets stopped. * This method may be implemented by a concrete subclass to handle actions * necessary for stopping the step (e.g. cleanup). The default implementation * does nothing. * * \return if the actions were done successfully; true on every call for the default implementation */ virtual bool OnStopStep() { return true; } /** * \brief Called when restarting a navigation step. * This method may be implemented by a concrete subclass to handle actions * necessary for restarting the navigation step. The default implementations * calls OnStopStep() followed by OnStartStep(). * * \return if the actions were done successfully */ virtual bool OnRestartStep(); /** * \brief Called when all necessary actions for the step where done. * This method has to be implemented by a concrete subclass to handle actions * necessary for finishing the navigation step. * * \return if the actions were done successfully */ virtual bool OnFinishStep() = 0; /** * \brief Called when the navigation step gets activated. * This method has to be implemented by a concrete subclass to handle actions * necessary on activating the navigation step. * * \return if the actions were done successfully */ virtual bool OnActivateStep() = 0; /** * \brief Called when the navigation step gets deactivated (-> state started). * This method may be implemented by a concrete subclass to handle actions * necessary on deactivating the navigation step, which means switching to * another step. * * \return if the actions were done successfully; true on every call for the default implementation */ virtual bool OnDeactivateStep() { return true; } /** * \brief Called periodically while a navigation step is active. * This method has to be implemented by a concrete subclass to handle all * periodic actions during the navigation step. */ virtual void OnUpdate() = 0; /** * \brief Called every time SetCombinedModality() was called. * This method may be implemented by a concrete subclass to handle this event. * The default implementation does nothing. */ virtual void OnSetCombinedModality() { } /** * \brief Returns the data storage set for the navigation step. * * \param throwNull if this method should throw an exception when the data storage is null (default: true) * \return the data storage set by SetDataStorage(); can only be null if the parameter throwNull is set to false * \throws mitk::Exception if the data storage is null and the parameter throwNull is set to true */ itk::SmartPointer GetDataStorage(bool throwNull = true); /** * \brief Returns the combined modality set for the navigation step. * * \param throwNull if this method should throw an exception when the combined modality is null (default: true) * \return the combined modality set by SetCombinedModality(); can only be null if the parameter throwNull is set to false * \throws mitk::Exception if the combined modality is null and the parameter throwNull is set to true */ - itk::SmartPointer GetCombinedModality(bool throwNull = true); + itk::SmartPointer GetCombinedModality(bool throwNull = true); /** * \brief Returns node with the given name and the given source node (parent) from the data storage. * * \param name the name of the node which should be got from the data storage * \param sourceName name of the source node under which the node should be searched * \return node with the given name or null if no node with the given name and source node could be found * \throws mitk::Exception if the data storage (can be set by SetDataStorage()) is null */ itk::SmartPointer GetNamedDerivedNode(const char* name, const char* sourceName); /** * \brief Returns node with the given name and the given source node (parent) from the data storage. * The node is created if no matching node was found. * * \param name the name of the node which should be got from the data storage * \param sourceName name of the source node under which the node should be searched * \return node with the given name * \throws mitk::Exception if the data storage (can be set by SetDataStorage()) is null */ itk::SmartPointer GetNamedDerivedNodeAndCreate(const char* name, const char* sourceName); private: itk::SmartPointer m_DataStorage; - itk::SmartPointer m_CombinedModality; + itk::SmartPointer m_CombinedModality; NavigationStepState m_NavigationStepState; }; #endif // QMITKUSABSTRACTNAVIGATIONSTEP_H diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepCombinedModality.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepCombinedModality.cpp index 00ab7836c7..586eead09a 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepCombinedModality.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepCombinedModality.cpp @@ -1,428 +1,430 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkUSNavigationStepCombinedModality.h" #include "ui_QmitkUSNavigationStepCombinedModality.h" +#include "mitkAbstractUltrasoundTrackerDevice.h" #include "mitkUSCombinedModality.h" + #include "../Widgets/QmitkUSCombinedModalityEditWidget.h" #include #include #include #include "mitkBaseRenderer.h" QmitkUSNavigationStepCombinedModality::QmitkUSNavigationStepCombinedModality(QWidget *parent) : QmitkUSAbstractNavigationStep(parent), m_LastCalibrationFilename(""), m_CalibrationLoadedNecessary(true), m_ListenerDeviceChanged(this, &QmitkUSNavigationStepCombinedModality::OnDevicePropertyChanged), ui(new Ui::QmitkUSNavigationStepCombinedModality) { ui->setupUi(this); // combined modality create widget should only be visible after button press ui->combinedModalityCreateWidget->setVisible(false); ui->combinedModalityEditWidget->setVisible(false); connect(ui->combinedModalityListWidget, SIGNAL(ServiceSelectionChanged(us::ServiceReferenceU)), this, SLOT(OnDeviceSelectionChanged())); connect(ui->combinedModalityListWidget, SIGNAL(ServiceModified(us::ServiceReferenceU)), this, SLOT(OnDeviceSelectionChanged())); connect(ui->combinedModalityCreateWidget, SIGNAL(SignalAborted()), this, SLOT(OnCombinedModalityCreationExit())); connect(ui->combinedModalityCreateWidget, SIGNAL(SignalCreated()), this, SLOT(OnCombinedModalityCreationExit())); connect(ui->combinedModalityEditWidget, SIGNAL(SignalAborted()), this, SLOT(OnCombinedModalityEditExit())); connect(ui->combinedModalityEditWidget, SIGNAL(SignalSaved()), this, SLOT(OnCombinedModalityEditExit())); - std::string filterOnlyCombinedModalities = "(&(" + us::ServiceConstants::OBJECTCLASS() + "=" + "org.mitk.services.USCombinedModality)(" + mitk::USCombinedModality::GetPropertyKeys().US_PROPKEY_CLASS + "=" + mitk::USCombinedModality::DeviceClassIdentifier + "))"; + std::string filterOnlyCombinedModalities = "(&(" + us::ServiceConstants::OBJECTCLASS() + "=" + "org.mitk.services.AbstractUltrasoundTrackerDevice)(" + mitk::AbstractUltrasoundTrackerDevice::US_PROPKEY_CLASS + "=" + mitk::AbstractUltrasoundTrackerDevice::DeviceClassIdentifier + "))"; //std::string filter = "(&(" + us::ServiceConstants::OBJECTCLASS() + "=" + "org.mitk.services.UltrasoundDevice))"; - ui->combinedModalityListWidget->Initialize(mitk::USCombinedModality::US_PROPKEY_DEVICENAME); + ui->combinedModalityListWidget->Initialize(filterOnlyCombinedModalities); ui->combinedModalityListWidget->SetAutomaticallySelectFirstEntry(true); //try to load UI settings QSettings settings; settings.beginGroup(QString::fromStdString("QmitkUSNavigationStepCombinedModality")); m_LastCalibrationFilename = settings.value("LastCalibrationFilename", QVariant("")).toString().toStdString(); MITK_DEBUG << "PERSISTENCE load: " << m_LastCalibrationFilename; settings.endGroup(); } QmitkUSNavigationStepCombinedModality::~QmitkUSNavigationStepCombinedModality() { ui->combinedModalityListWidget->blockSignals(true); //save UI settings QSettings settings; settings.beginGroup(QString::fromStdString("QmitkUSNavigationStepCombinedModality")); settings.setValue("LastCalibrationFilename", QVariant(m_LastCalibrationFilename.c_str())); settings.endGroup(); MITK_DEBUG << "PERSISTENCE save: " << m_LastCalibrationFilename; //delete UI delete ui; } void QmitkUSNavigationStepCombinedModality::OnDeviceSelectionChanged() { - mitk::USCombinedModality::Pointer combinedModality = this->GetSelectedCombinedModality(); + mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->GetSelectedCombinedModality(); bool combinedModalitySelected = combinedModality.IsNotNull(); ui->calibrationGroupBox->setEnabled(combinedModalitySelected); ui->combinedModalityDeleteButton->setEnabled(combinedModalitySelected); ui->combinedModalitEditButton->setEnabled(combinedModalitySelected); if (!combinedModalitySelected || m_CombinedModality != combinedModality) { emit SignalNoLongerReadyForNextStep(); if (m_CombinedModality.IsNotNull() && m_CombinedModality->GetUltrasoundDevice().IsNotNull()) { m_CombinedModality->GetUltrasoundDevice()->RemovePropertyChangedListener(m_ListenerDeviceChanged); } if (combinedModalitySelected && combinedModality->GetUltrasoundDevice().IsNotNull()) { combinedModality->GetUltrasoundDevice()->RemovePropertyChangedListener(m_ListenerDeviceChanged); } } m_CombinedModality = combinedModality; if (combinedModalitySelected) { bool calibrated = this->UpdateCalibrationState(); if (!m_CalibrationLoadedNecessary) { emit SignalReadyForNextStep(); } else { if (calibrated) { emit SignalReadyForNextStep(); } else { emit SignalNoLongerReadyForNextStep(); } } // enable disconnect button only if combined modality is connected or active - ui->combinedModalityDistconnectButton->setEnabled(combinedModality->GetDeviceState() >= mitk::USCombinedModality::State_Connected); - ui->combinedModalityActivateButton->setEnabled(combinedModality->GetDeviceState() < mitk::USCombinedModality::State_Activated); + ui->combinedModalityDistconnectButton->setEnabled(combinedModality->GetUltrasoundDevice()->GetDeviceState() >= mitk::USDevice::State_Connected); + ui->combinedModalityActivateButton->setEnabled(combinedModality->GetUltrasoundDevice()->GetDeviceState() < mitk::USDevice::State_Activated); this->UpdateTrackingToolNames(); } else { ui->combinedModalityDistconnectButton->setEnabled(false); ui->combinedModalityActivateButton->setEnabled(false); } } void QmitkUSNavigationStepCombinedModality::OnLoadCalibration() { QString filename = QFileDialog::getOpenFileName(QApplication::activeWindow(), "Load Calibration", m_LastCalibrationFilename.c_str(), "Calibration files *.cal"); m_LastCalibrationFilename = filename.toStdString(); - mitk::USCombinedModality::Pointer combinedModality = this->GetSelectedCombinedModality(); + mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->GetSelectedCombinedModality(); if (combinedModality.IsNull()) { ui->calibrationLoadStateLabel->setText("Selected device is no USCombinedModality."); emit SignalNoLongerReadyForNextStep(); return; } if (filename.isEmpty()) { bool calibrated = this->UpdateCalibrationState(); if (!calibrated) { emit SignalNoLongerReadyForNextStep(); } return; } QFile file(filename); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { MITK_WARN << "Cannot open file '" << filename.toStdString() << "' for reading."; ui->calibrationLoadStateLabel->setText("Cannot open file '" + filename + "' for reading."); emit SignalNoLongerReadyForNextStep(); return; } QTextStream inStream(&file); m_LoadedCalibration = inStream.readAll().toStdString(); if (m_LoadedCalibration.empty()) { MITK_WARN << "Failed to load file. Unsupported format?"; ui->calibrationLoadStateLabel->setText("Failed to load file. Unsupported format?"); emit SignalNoLongerReadyForNextStep(); return; } try { combinedModality->DeserializeCalibration(m_LoadedCalibration); } catch (const mitk::Exception& /*exception*/) { MITK_WARN << "Failed to deserialize calibration. Unsuppoerted format?"; ui->calibrationLoadStateLabel->setText("Failed to deserialize calibration. Unsuppoerted format?"); emit SignalNoLongerReadyForNextStep(); return; } ui->calibrationLoadStateLabel->setText("Loaded calibration : " + filename); m_CombinedModality = combinedModality; emit SignalReadyForNextStep(); } void QmitkUSNavigationStepCombinedModality::OnCombinedModalityCreateNewButtonClicked() { this->SetCombinedModalityCreateWidgetEnabled(true); } void QmitkUSNavigationStepCombinedModality::OnCombinedModalityCreationExit() { this->SetCombinedModalityCreateWidgetEnabled(false); mitk::DataNode::Pointer usNode = mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))->GetDataStorage()//GetDataStorage ->GetNamedNode("US Viewing Stream - Image 0"); if (usNode.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews(//Reinit usNode->GetData()->GetTimeGeometry());//GetNode } else { mitkThrow()<< "No reinit possible"; } } void QmitkUSNavigationStepCombinedModality::OnCombinedModalityEditExit() { this->SetCombinedModalityEditWidgetEnabled(false); ui->combinedModalityEditWidget->SetCombinedModality(0); } void QmitkUSNavigationStepCombinedModality::OnDeleteButtonClicked() { - mitk::USCombinedModality::Pointer combinedModality = this->GetSelectedCombinedModality(); + mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->GetSelectedCombinedModality(); if (combinedModality.IsNotNull()) { combinedModality->RemoveAllObservers(); combinedModality->UnregisterOnService(); } } void QmitkUSNavigationStepCombinedModality::OnCombinedModalityEditButtonClicked() { ui->combinedModalityEditWidget->SetCombinedModality(m_CombinedModality); this->SetCombinedModalityEditWidgetEnabled(true); } void QmitkUSNavigationStepCombinedModality::OnActivateButtonClicked() { - mitk::USCombinedModality::Pointer combinedModality = this->GetSelectedCombinedModality(); + mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->GetSelectedCombinedModality(); if (combinedModality.IsNotNull()) { - if (!combinedModality->GetIsConnected()) { combinedModality->Connect(); } - if (!combinedModality->GetIsActive()) { combinedModality->Activate(); } + if (!combinedModality->GetUltrasoundDevice()->GetIsConnected()) { combinedModality->GetUltrasoundDevice()->Connect(); } + if (!combinedModality->GetUltrasoundDevice()->GetIsActive()) { combinedModality->GetUltrasoundDevice()->Activate(); } } } void QmitkUSNavigationStepCombinedModality::OnDisconnectButtonClicked() { - mitk::USCombinedModality::Pointer combinedModality = this->GetSelectedCombinedModality(); + mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->GetSelectedCombinedModality(); if (combinedModality.IsNotNull()) { - if (combinedModality->GetIsActive()) { combinedModality->Deactivate(); } - if (combinedModality->GetIsConnected()) { combinedModality->Disconnect(); } + if (combinedModality->GetUltrasoundDevice()->GetIsActive()) { combinedModality->GetUltrasoundDevice()->Deactivate(); } + if (combinedModality->GetUltrasoundDevice()->GetIsConnected()) { combinedModality->GetUltrasoundDevice()->Disconnect(); } } } bool QmitkUSNavigationStepCombinedModality::OnStartStep() { return true; } bool QmitkUSNavigationStepCombinedModality::OnRestartStep() { return true; } bool QmitkUSNavigationStepCombinedModality::OnFinishStep() { - mitk::USCombinedModality::Pointer combinedModality = this->GetSelectedCombinedModality(); + mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->GetSelectedCombinedModality(); if (combinedModality.IsNotNull()) { QApplication::setOverrideCursor(Qt::WaitCursor); // make sure that the combined modality is in connected state before using it - if (combinedModality->GetDeviceState() < mitk::USDevice::State_Connected) { combinedModality->Connect(); } - if (combinedModality->GetDeviceState() < mitk::USDevice::State_Activated) { combinedModality->Activate(); } + if (combinedModality->GetUltrasoundDevice()->GetDeviceState() < mitk::USDevice::State_Connected) { combinedModality->GetUltrasoundDevice()->Connect(); } + if (combinedModality->GetUltrasoundDevice()->GetDeviceState() < mitk::USDevice::State_Activated) { combinedModality->GetUltrasoundDevice()->Activate(); } QApplication::restoreOverrideCursor(); } emit SignalCombinedModalityChanged(combinedModality); this->CreateCombinedModalityResultAndSignalIt(); return true; } bool QmitkUSNavigationStepCombinedModality::OnActivateStep() { // make sure that device selection status is up-to-date this->OnDeviceSelectionChanged(); return true; } void QmitkUSNavigationStepCombinedModality::OnUpdate() { } QString QmitkUSNavigationStepCombinedModality::GetTitle() { return "Selection of Combined Modality"; } bool QmitkUSNavigationStepCombinedModality::GetIsRestartable() { return false; } void QmitkUSNavigationStepCombinedModality::SetCombinedModalityCreateWidgetEnabled(bool enabled) { ui->combinedModalityLabel->setVisible(!enabled); ui->combinedModalityListWidget->setVisible(!enabled); ui->combinedModalityCreateButton->setVisible(!enabled); ui->combinedModalityDeleteButton->setVisible(!enabled); ui->combinedModalitEditButton->setVisible(!enabled); ui->combinedModalityActivateButton->setVisible(!enabled); ui->combinedModalityDistconnectButton->setVisible(!enabled); ui->helpLabel->setVisible(!enabled); ui->calibrationGroupBox->setVisible(!enabled); ui->combinedModalityCreateWidget->setVisible(enabled); } void QmitkUSNavigationStepCombinedModality::SetCombinedModalityEditWidgetEnabled(bool enabled) { ui->combinedModalityLabel->setVisible(!enabled); ui->combinedModalityListWidget->setVisible(!enabled); ui->combinedModalityCreateButton->setVisible(!enabled); ui->combinedModalityDeleteButton->setVisible(!enabled); ui->combinedModalitEditButton->setVisible(!enabled); ui->combinedModalityActivateButton->setVisible(!enabled); ui->combinedModalityDistconnectButton->setVisible(!enabled); ui->helpLabel->setVisible(!enabled); ui->calibrationGroupBox->setVisible(!enabled); ui->combinedModalityEditWidget->setVisible(enabled); } void QmitkUSNavigationStepCombinedModality::CreateCombinedModalityResultAndSignalIt() { - mitk::USCombinedModality::Pointer combinedModality = this->GetCombinedModality(); + mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->GetCombinedModality(); mitk::USDevice::Pointer usDevice = combinedModality->GetUltrasoundDevice(); // save identifiers and calibration to a result object mitk::DataNode::Pointer combinedModalityResult = mitk::DataNode::New(); combinedModalityResult->SetName("CombinedModalityResult"); combinedModalityResult->SetStringProperty("USNavigation::CombinedModality", - std::string(combinedModality->GetManufacturer() + ": " + combinedModality->GetName() - + " (" + combinedModality->GetComment() + ")").c_str()); + std::string(combinedModality->GetUltrasoundDevice()->GetManufacturer() + ": " + combinedModality->GetUltrasoundDevice()->GetName() + + " (" + combinedModality->GetUltrasoundDevice()->GetComment() + ")").c_str()); combinedModalityResult->SetStringProperty("USNavigation::UltrasoundDevice", std::string(usDevice->GetManufacturer() + ": " + usDevice->GetName() + " (" + usDevice->GetComment() + ")").c_str()); combinedModalityResult->SetStringProperty("USNavigation::TrackingDevice", combinedModality->GetNavigationDataSource()->GetName().c_str()); combinedModalityResult->SetStringProperty("USNavigation::Calibration", combinedModality->SerializeCalibration().c_str()); emit SignalIntermediateResult(combinedModalityResult); } bool QmitkUSNavigationStepCombinedModality::UpdateCalibrationState() { if (m_CombinedModality.IsNull()) { return false; } bool calibrated = m_CombinedModality->GetContainsAtLeastOneCalibration(); if (calibrated) { ui->calibrationLoadStateLabel->setText("Selected device contains at least one calibration."); } else { ui->calibrationLoadStateLabel->setText("Selected device is not calibrated."); } return calibrated; } -mitk::USCombinedModality::Pointer QmitkUSNavigationStepCombinedModality::GetSelectedCombinedModality() +mitk::AbstractUltrasoundTrackerDevice::Pointer QmitkUSNavigationStepCombinedModality::GetSelectedCombinedModality() { // nothing more to do if no device is selected at the moment if (!ui->combinedModalityListWidget->GetIsServiceSelected()) { return 0; } - mitk::USCombinedModality::Pointer combinedModality = ui->combinedModalityListWidget->GetSelectedService(); + mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = ui->combinedModalityListWidget->GetSelectedService(); if (combinedModality.IsNull()) { MITK_WARN << "Selected device is no USCombinedModality."; } return combinedModality; } void QmitkUSNavigationStepCombinedModality::SetCalibrationLoadedNecessary(bool necessary) { m_CalibrationLoadedNecessary = necessary; } void QmitkUSNavigationStepCombinedModality::OnDevicePropertyChanged(const std::string& key, const std::string&) { // property changes only matter if the navigation step is currently active // (being sensitive to them in other states may even be dangerous) if (this->GetNavigationStepState() < QmitkUSAbstractNavigationStep::State_Active) { return; } // calibration state could have changed if the depth was changed if (key == mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH) { bool calibrated = this->UpdateCalibrationState(); if (calibrated) { emit SignalReadyForNextStep(); } else { emit SignalNoLongerReadyForNextStep(); } } } void QmitkUSNavigationStepCombinedModality::UpdateTrackingToolNames() { //check if everything is initialized if (m_CombinedModality.IsNull()) { return; } mitk::NavigationDataSource::Pointer navigationDataSource = m_CombinedModality->GetNavigationDataSource(); if (navigationDataSource.IsNull()) { return; } if (GetDataStorage(false).IsNull()) { return; } // get the settings node mitk::DataNode::Pointer settingsNode = this->GetNamedDerivedNode(DATANAME_SETTINGS, DATANAME_BASENODE); std::string needleNames; itk::ProcessObject::DataObjectPointerArray outputs = navigationDataSource->GetOutputs(); for (itk::ProcessObject::DataObjectPointerArray::iterator it = outputs.begin(); it != outputs.end(); ++it) { needleNames += std::string((static_cast(it->GetPointer()))->GetName()) + ";"; } // change the settings node only if the settings changed std::string oldProperty; if (!settingsNode->GetStringProperty("settings.needle-names", oldProperty) || oldProperty != needleNames || !settingsNode->GetStringProperty("settings.reference-names", oldProperty) || oldProperty != needleNames) { settingsNode->SetStringProperty("settings.needle-names", needleNames.c_str()); settingsNode->SetStringProperty("settings.reference-names", needleNames.c_str()); emit SignalSettingsNodeChanged(settingsNode); } } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepCombinedModality.h b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepCombinedModality.h index 66d9f22848..2df8b2dd3a 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepCombinedModality.h +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepCombinedModality.h @@ -1,122 +1,122 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKUSNAVIGATIONSTEPCOMBINEDMODALITY_H #define QMITKUSNAVIGATIONSTEPCOMBINEDMODALITY_H #include "QmitkUSAbstractNavigationStep.h" namespace Ui { class QmitkUSNavigationStepCombinedModality; } /** * \brief Navigation step for creating and selecting a combined modality. * Already created combined modalities can be selected from a service list * widget and calibrations can be loaded for them. New combined modalities can * be created from two service list widgets of NavigationDataSources and * USDevices. */ class QmitkUSNavigationStepCombinedModality : public QmitkUSAbstractNavigationStep { Q_OBJECT protected slots: /** * \brief Triggered, when the selection in the service list widget has changed. */ void OnDeviceSelectionChanged(); /** * \brief Triggered, when the user has clicked "Load Calibration". * Opens a file open dialog and sets the selected calibration for the selected * combined modality. */ void OnLoadCalibration(); /** * \brief Triggered, when the button for creating a new combined modality was clicked. */ void OnCombinedModalityCreateNewButtonClicked(); /** * \brief Triggered, when the dialog for creating a new combined modality was closed. */ void OnCombinedModalityCreationExit(); void OnCombinedModalityEditExit(); /** * \brief Triggered, when the button for deleting a combined modality was clicked. * Unregisters the combined modality from the microservice and removes it. */ void OnDeleteButtonClicked(); void OnCombinedModalityEditButtonClicked(); void OnActivateButtonClicked(); /** * \brief Triggered, when the button for disconnecting a combined modality was clicked. * The state of the combined modality is changed to 'initialized'. */ void OnDisconnectButtonClicked(); public: explicit QmitkUSNavigationStepCombinedModality(QWidget *parent = 0); ~QmitkUSNavigationStepCombinedModality(); virtual bool OnStartStep(); virtual bool OnRestartStep(); virtual bool OnFinishStep(); virtual bool OnActivateStep(); virtual void OnUpdate(); virtual QString GetTitle(); virtual bool GetIsRestartable(); - mitk::USCombinedModality::Pointer GetSelectedCombinedModality(); + mitk::AbstractUltrasoundTrackerDevice::Pointer GetSelectedCombinedModality(); void SetCalibrationLoadedNecessary(bool); void OnDevicePropertyChanged(const std::string&, const std::string&); protected: void SetCombinedModalityCreateWidgetEnabled(bool enabled); void SetCombinedModalityEditWidgetEnabled(bool enabled); void CreateCombinedModalityResultAndSignalIt(); bool UpdateCalibrationState(); void UpdateTrackingToolNames(); /** * \brief The Combined Modality which was selected by the user. */ - itk::SmartPointer m_CombinedModality; + itk::SmartPointer m_CombinedModality; std::string m_LoadedCalibration; //<<< Temporary saving point for loaded calibration data. std::string m_LastCalibrationFilename; //<<< saves the filename last loaded calibration bool m_CalibrationLoadedNecessary; private: mitk::MessageDelegate2 m_ListenerDeviceChanged; Ui::QmitkUSNavigationStepCombinedModality *ui; }; #endif // QMITKUSNAVIGATIONSTEPCOMBINEDMODALITY_H diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepMarkerIntervention.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepMarkerIntervention.cpp index 3c6f6514df..1449cdcfee 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepMarkerIntervention.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepMarkerIntervention.cpp @@ -1,1017 +1,1017 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkUSNavigationStepMarkerIntervention.h" #include "ui_QmitkUSNavigationStepMarkerIntervention.h" #include "mitkBaseRenderer.h" #include "mitkContourModel.h" #include "mitkNeedleProjectionFilter.h" #include "mitkNodeDisplacementFilter.h" #include "mitkSurface.h" #include "mitkTextAnnotation2D.h" #include #include #include "../Filter/mitkUSNavigationTargetIntersectionFilter.h" #include "../Filter/mitkUSNavigationTargetOcclusionFilter.h" #include "../Filter/mitkUSNavigationTargetUpdateFilter.h" #include "../QmitkUSNavigationMarkerPlacement.h" #include "../Widgets/QmitkZoneProgressBar.h" #include "../mitkUSTargetPlacementQualityCalculator.h" #include "../Interactors/mitkUSPointMarkInteractor.h" #include "usModuleRegistry.h" #include "mitkLookupTable.h" #include "mitkLookupTableProperty.h" #include "mitkSurface.h" // VTK #include "vtkCellLocator.h" #include "vtkDataSet.h" #include "vtkDoubleArray.h" #include "vtkFloatArray.h" #include "vtkIdList.h" #include "vtkLinearTransform.h" #include "vtkLookupTable.h" #include "vtkMath.h" #include "vtkOBBTree.h" #include "vtkPointData.h" #include "vtkPointData.h" #include "vtkPolyData.h" #include "vtkSelectEnclosedPoints.h" #include "vtkSmartPointer.h" #include "vtkSphereSource.h" #include "vtkTransformPolyDataFilter.h" #include "vtkWarpScalar.h" QmitkUSNavigationStepMarkerIntervention::QmitkUSNavigationStepMarkerIntervention(QWidget *parent) : QmitkUSAbstractNavigationStep(parent), m_NumberOfTargets(0), m_PlannedTargetsNodes(), m_ReachedTargetsNodes(), m_TargetProgressBar(new QmitkZoneProgressBar(QString::fromStdString("Target: %1 mm"), 200, 0, this)), m_PlannedTargetProgressBar(nullptr), m_CurrentTargetIndex(0), m_CurrentTargetReached(false), m_ShowPlanningColors(false), m_PointMarkInteractor(mitk::USPointMarkInteractor::New()), m_TargetNode(nullptr), m_TargetColorLookupTableProperty(nullptr), m_TargetSurface(nullptr), m_NeedleProjectionFilter(mitk::NeedleProjectionFilter::New()), m_NodeDisplacementFilter(mitk::NodeDisplacementFilter::New()), m_TargetUpdateFilter(mitk::USNavigationTargetUpdateFilter::New()), m_TargetOcclusionFilter(mitk::USNavigationTargetOcclusionFilter::New()), m_TargetIntersectionFilter(mitk::USNavigationTargetIntersectionFilter::New()), m_PlacementQualityCalculator(mitk::USTargetPlacementQualityCalculator::New()), m_TargetStructureWarnOverlay(mitk::TextAnnotation2D::New()), m_ReferenceSensorName(), m_NeedleSensorName(), m_ReferenceSensorIndex(1), m_NeedleSensorIndex(0), m_ListenerTargetCoordinatesChanged(this, &QmitkUSNavigationStepMarkerIntervention::UpdateTargetCoordinates), ui(new Ui::QmitkUSNavigationStepMarkerIntervention) { m_ActiveTargetColor[0] = 1; m_ActiveTargetColor[1] = 1; m_ActiveTargetColor[2] = 0; m_InactiveTargetColor[0] = 1; m_InactiveTargetColor[1] = 1; m_InactiveTargetColor[2] = 0.5; m_ReachedTargetColor[0] = 0.6; m_ReachedTargetColor[1] = 1; m_ReachedTargetColor[2] = 0.6; ui->setupUi(this); connect(ui->freezeImageButton, SIGNAL(SignalFreezed(bool)), this, SLOT(OnFreeze(bool))); connect(ui->backToLastTargetButton, SIGNAL(clicked()), this, SLOT(OnBackToLastTargetClicked())); connect(ui->targetReachedButton, SIGNAL(clicked()), this, SLOT(OnTargetLeft())); connect(this, SIGNAL(TargetReached(int)), this, SLOT(OnTargetReached())); connect(this, SIGNAL(TargetLeft(int)), this, SLOT(OnTargetLeft())); connect(ui->riskStructuresRangeWidget, SIGNAL(SignalZoneViolated(const mitk::DataNode *, mitk::Point3D)), this, SLOT(OnRiskZoneViolated(const mitk::DataNode *, mitk::Point3D))); m_PointMarkInteractor->CoordinatesChangedEvent.AddListener(m_ListenerTargetCoordinatesChanged); this->GenerateTargetColorLookupTable(); m_TargetProgressBar->SetTextFormatInvalid("Target is not on Needle Path"); ui->targetStructuresRangeLayout->addWidget(m_TargetProgressBar); m_TargetUpdateFilter->SetScalarArrayIdentifier("USNavigation::ReachedTargetScores"); } QmitkUSNavigationStepMarkerIntervention::~QmitkUSNavigationStepMarkerIntervention() { mitk::DataStorage::Pointer dataStorage = this->GetDataStorage(false); if (dataStorage.IsNotNull()) { // remove the node for the needle path mitk::DataNode::Pointer node = this->GetNamedDerivedNode("Needle Path", QmitkUSAbstractNavigationStep::DATANAME_BASENODE); if (node.IsNotNull()) { dataStorage->Remove(node); } } delete ui; m_PointMarkInteractor->CoordinatesChangedEvent.RemoveListener(m_ListenerTargetCoordinatesChanged); } bool QmitkUSNavigationStepMarkerIntervention::OnStartStep() { m_NeedleProjectionFilter->SelectInput(m_NeedleSensorIndex); // create node for Needle Projection mitk::DataNode::Pointer node = this->GetNamedDerivedNodeAndCreate("Needle Path", QmitkUSAbstractNavigationStep::DATANAME_BASENODE); node->SetData(m_NeedleProjectionFilter->GetProjection()); node->SetBoolProperty("show contour", true); // initialize warning overlay (and do not display it, yet) m_TargetStructureWarnOverlay->SetText("Warning: Needle is Inside the Target Structure."); m_TargetStructureWarnOverlay->SetVisibility(false); // set position and font size for the text overlay mitk::Point2D overlayPosition; overlayPosition.SetElement(0, 10.0f); overlayPosition.SetElement(1, 10.0f); m_TargetStructureWarnOverlay->SetPosition2D(overlayPosition); m_TargetStructureWarnOverlay->SetFontSize(18); // overlay should be red mitk::Color color; color[0] = 1; color[1] = 0; color[2] = 0; m_TargetStructureWarnOverlay->SetColor(color); mitk::ManualPlacementAnnotationRenderer::AddAnnotation(m_TargetStructureWarnOverlay.GetPointer(), "stdmulti.widget4"); return true; } bool QmitkUSNavigationStepMarkerIntervention::OnStopStep() { mitk::DataStorage::Pointer dataStorage = this->GetDataStorage(); // remove all reached nodes from the data storage for (QVector>::iterator it = m_ReachedTargetsNodes.begin(); it != m_ReachedTargetsNodes.end(); ++it) { dataStorage->Remove(*it); } m_ReachedTargetsNodes.clear(); m_CurrentTargetIndex = 0; // reset button states ui->freezeImageButton->setEnabled(false); ui->backToLastTargetButton->setEnabled(false); ui->targetReachedButton->setEnabled(true); // make sure that it is unfreezed after stopping the step ui->freezeImageButton->Unfreeze(); // remove base node for reached targets from the data storage mitk::DataNode::Pointer reachedTargetsNode = this->GetNamedDerivedNode( QmitkUSAbstractNavigationStep::DATANAME_BASENODE, QmitkUSNavigationMarkerPlacement::DATANAME_REACHED_TARGETS); if (reachedTargetsNode.IsNotNull()) { dataStorage->Remove(reachedTargetsNode); } return true; } bool QmitkUSNavigationStepMarkerIntervention::OnFinishStep() { return true; } bool QmitkUSNavigationStepMarkerIntervention::OnActivateStep() { this->ClearZones(); // clear risk zones before adding new ones // get target node from data storage and make sure that it contains data m_TargetNode = this->GetNamedDerivedNode(QmitkUSNavigationMarkerPlacement::DATANAME_TARGETSURFACE, QmitkUSNavigationMarkerPlacement::DATANAME_TUMOUR); if (m_TargetNode.IsNull() || m_TargetNode->GetData() == 0) { mitkThrow() << "Target node (" << QmitkUSNavigationMarkerPlacement::DATANAME_TARGETSURFACE << ") must not be null."; } // get target data and make sure that it is a surface m_TargetSurface = dynamic_cast(m_TargetNode->GetData()); if (m_TargetSurface.IsNull()) { mitkThrow() << "Target node (" << QmitkUSNavigationMarkerPlacement::DATANAME_TARGETSURFACE << ") data must be of type mitk::Surface"; } // delete progress bars for reinitializing them again afterwards if (m_PlannedTargetProgressBar) { ui->targetStructuresRangeLayout->removeWidget(m_PlannedTargetProgressBar); delete m_PlannedTargetProgressBar; m_PlannedTargetProgressBar = 0; } m_NodeDisplacementFilter->SelectInput(m_ReferenceSensorIndex); this->UpdateTargetProgressDisplay(); mitk::DataNode::Pointer tumourNode = this->GetNamedDerivedNode(QmitkUSNavigationMarkerPlacement::DATANAME_TUMOUR, QmitkUSAbstractNavigationStep::DATANAME_BASENODE); if (tumourNode.IsNotNull()) { // do not show tumour node during intervention (target surface is shown) tumourNode->SetBoolProperty("visible", false); // add tumour as a risk structure ui->riskStructuresRangeWidget->AddZone(tumourNode); } // set target structure for target update filter m_TargetUpdateFilter->SetTargetStructure(m_TargetNode); m_TargetOcclusionFilter->SetTargetStructure(m_TargetNode); // set lookup table of tumour node m_TargetNode->SetProperty("LookupTable", m_TargetColorLookupTableProperty); // mitk::DataNode::Pointer targetsBaseNode = this->GetNamedDerivedNode(QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS, QmitkUSAbstractNavigationStep::DATANAME_BASENODE); mitk::DataStorage::SetOfObjects::ConstPointer plannedTargetNodes; if (targetsBaseNode.IsNotNull()) { plannedTargetNodes = this->GetDataStorage()->GetDerivations(targetsBaseNode); } if (plannedTargetNodes.IsNotNull() && plannedTargetNodes->Size() > 0) { for (mitk::DataStorage::SetOfObjects::ConstIterator it = plannedTargetNodes->Begin(); it != plannedTargetNodes->End(); ++it) { m_PlannedTargetsNodes.push_back(it->Value()); } m_PlannedTargetProgressBar = new QmitkZoneProgressBar(QString::fromStdString("Planned Target"), 200, 0); ui->targetStructuresRangeLayout->addWidget(m_PlannedTargetProgressBar); } // add progress bars for risk zone nodes mitk::DataNode::Pointer zonesBaseNode = this->GetNamedDerivedNode(QmitkUSNavigationMarkerPlacement::DATANAME_ZONES, QmitkUSAbstractNavigationStep::DATANAME_BASENODE); // only add progress bars if the base node for zones was created if (zonesBaseNode.IsNotNull()) { mitk::DataStorage::SetOfObjects::ConstPointer zoneNodes = this->GetDataStorage()->GetDerivations(zonesBaseNode); for (mitk::DataStorage::SetOfObjects::ConstIterator it = zoneNodes->Begin(); it != zoneNodes->End(); ++it) { ui->riskStructuresRangeWidget->AddZone(it->Value()); } m_TargetOcclusionFilter->SelectStartPositionInput(m_NeedleSensorIndex); m_TargetOcclusionFilter->SetObstacleStructures(zoneNodes); } return true; } bool QmitkUSNavigationStepMarkerIntervention::OnDeactivateStep() { ui->freezeImageButton->Unfreeze(); return true; } void QmitkUSNavigationStepMarkerIntervention::OnUpdate() { // get navigation data source and make sure that it is not null mitk::NavigationDataSource::Pointer navigationDataSource = this->GetCombinedModality()->GetNavigationDataSource(); if (navigationDataSource.IsNull()) { MITK_ERROR("QmitkUSAbstractNavigationStep") ("QmitkUSNavigationStepMarkerIntervention") << "Navigation Data Source of Combined Modality must not be null."; mitkThrow() << "Navigation Data Source of Combined Modality must not be null."; } ui->riskStructuresRangeWidget->UpdateDistancesToNeedlePosition(navigationDataSource->GetOutput(m_NeedleSensorIndex)); this->UpdateBodyMarkerStatus(navigationDataSource->GetOutput(m_ReferenceSensorIndex)); this->UpdateTargetColors(); this->UpdateTargetScore(); this->UpdateTargetViolationStatus(); } void QmitkUSNavigationStepMarkerIntervention::OnSettingsChanged(const itk::SmartPointer settingsNode) { if (settingsNode.IsNull()) { return; } int numberOfTargets; if (settingsNode->GetIntProperty("settings.number-of-targets", numberOfTargets)) { m_NumberOfTargets = numberOfTargets; m_TargetUpdateFilter->SetNumberOfTargets(numberOfTargets); m_PlacementQualityCalculator->SetOptimalAngle(m_TargetUpdateFilter->GetOptimalAngle()); } std::string referenceSensorName; if (settingsNode->GetStringProperty("settings.reference-name-selected", referenceSensorName)) { m_ReferenceSensorName = referenceSensorName; } std::string needleSensorName; if (settingsNode->GetStringProperty("settings.needle-name-selected", needleSensorName)) { m_NeedleSensorName = needleSensorName; } this->UpdateSensorsNames(); } QString QmitkUSNavigationStepMarkerIntervention::GetTitle() { return "Computer-assisted Intervention"; } bool QmitkUSNavigationStepMarkerIntervention::GetIsRestartable() { return true; } QmitkUSAbstractNavigationStep::FilterVector QmitkUSNavigationStepMarkerIntervention::GetFilter() { FilterVector filter; filter.push_back(m_NeedleProjectionFilter.GetPointer()); filter.push_back(m_NodeDisplacementFilter.GetPointer()); filter.push_back(m_TargetOcclusionFilter.GetPointer()); return filter; } void QmitkUSNavigationStepMarkerIntervention::OnSetCombinedModality() { - mitk::USCombinedModality::Pointer combinedModality = this->GetCombinedModality(false); + mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->GetCombinedModality(false); if (combinedModality.IsNotNull()) { mitk::AffineTransform3D::Pointer calibration = combinedModality->GetCalibration(); if (calibration.IsNotNull()) { m_NeedleProjectionFilter->SetTargetPlane(calibration); } } ui->freezeImageButton->SetCombinedModality(combinedModality, m_ReferenceSensorIndex); this->UpdateSensorsNames(); } void QmitkUSNavigationStepMarkerIntervention::OnTargetReached() { m_CurrentTargetReached = true; } void QmitkUSNavigationStepMarkerIntervention::OnTargetLeft() { m_CurrentTargetReached = false; m_CurrentTargetIndex++; if (m_CurrentTargetIndex >= 0 && static_cast(m_CurrentTargetIndex) >= m_NumberOfTargets) { ui->targetReachedButton->setDisabled(true); } ui->backToLastTargetButton->setEnabled(true); ui->freezeImageButton->setEnabled(true); this->UpdateTargetProgressDisplay(); if (m_ReachedTargetsNodes.size() < m_CurrentTargetIndex) { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetName( (QString("Target ") + QString("%1").arg(m_CurrentTargetIndex, 2, 10, QLatin1Char('0'))).toStdString()); this->GetDataStorage()->Add( node, this->GetNamedDerivedNodeAndCreate(QmitkUSNavigationMarkerPlacement::DATANAME_REACHED_TARGETS, QmitkUSAbstractNavigationStep::DATANAME_BASENODE)); m_ReachedTargetsNodes.push_back(node); } mitk::DataNode::Pointer node = m_ReachedTargetsNodes.at(m_CurrentTargetIndex - 1); mitk::Surface::Pointer zone = mitk::Surface::New(); // create a vtk sphere with given radius vtkSphereSource *vtkData = vtkSphereSource::New(); vtkData->SetRadius(5); vtkData->SetCenter(0, 0, 0); vtkData->Update(); zone->SetVtkPolyData(vtkData->GetOutput()); vtkData->Delete(); // set vtk sphere and origin to data node node->SetData(zone); node->GetData()->GetGeometry()->SetOrigin( this->GetCombinedModality()->GetNavigationDataSource()->GetOutput(m_NeedleSensorIndex)->GetPosition()); node->SetColor(0.2, 0.9, 0.2); this->UpdateTargetCoordinates(node); } void QmitkUSNavigationStepMarkerIntervention::OnBackToLastTargetClicked() { if (m_CurrentTargetIndex < 1) { MITK_WARN << "Cannot go back to last target as there is no last target."; return; } m_CurrentTargetIndex--; if (m_ReachedTargetsNodes.size() > m_CurrentTargetIndex) { this->GetDataStorage()->Remove(m_ReachedTargetsNodes.last()); MITK_INFO("QmitkUSAbstractNavigationStep") ("QmitkUSNavigationStepMarkerIntervention") << "Removed Target " << m_ReachedTargetsNodes.size(); m_ReachedTargetsNodes.pop_back(); } if (m_CurrentTargetIndex == 0) { ui->backToLastTargetButton->setDisabled(true); } if (m_CurrentTargetIndex >= 0 && static_cast(m_CurrentTargetIndex) < m_NumberOfTargets) { ui->targetReachedButton->setEnabled(true); } ui->freezeImageButton->setEnabled(false); ui->freezeImageButton->Unfreeze(); this->UpdateTargetProgressDisplay(); m_TargetUpdateFilter->RemovePositionOfTarget(m_CurrentTargetIndex); } void QmitkUSNavigationStepMarkerIntervention::OnFreeze(bool freezed) { if (freezed) { - this->GetCombinedModality()->SetIsFreezed(true); + this->GetCombinedModality()->GetUltrasoundDevice()->SetIsFreezed(true); // load state machine and event config for data interactor m_PointMarkInteractor->LoadStateMachine("USPointMarkInteractions.xml", us::ModuleRegistry::GetModule("MitkUS")); m_PointMarkInteractor->SetEventConfig("globalConfig.xml"); if (m_CurrentTargetIndex < 1) { mitkThrow() << "Current target index has to be greater zero when freeze button is clicked."; } if (m_ReachedTargetsNodes.size() < m_CurrentTargetIndex) { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetName( (QString("Target ") + QString("%1").arg(m_CurrentTargetIndex, 2, 10, QLatin1Char('0'))).toStdString()); this->GetDataStorage()->Add( node, this->GetNamedDerivedNodeAndCreate(QmitkUSNavigationMarkerPlacement::DATANAME_REACHED_TARGETS, QmitkUSAbstractNavigationStep::DATANAME_BASENODE)); m_ReachedTargetsNodes.push_back(node); } m_PointMarkInteractor->SetDataNode(m_ReachedTargetsNodes.last()); } else { m_PointMarkInteractor->SetDataNode(0); - this->GetCombinedModality()->SetIsFreezed(false); + this->GetCombinedModality()->GetUltrasoundDevice()->SetIsFreezed(false); } } void QmitkUSNavigationStepMarkerIntervention::OnShowPlanningView(bool show) { m_ShowPlanningColors = show; } void QmitkUSNavigationStepMarkerIntervention::OnRiskZoneViolated(const mitk::DataNode *node, mitk::Point3D position) { MITK_INFO << "Risk zone (" << node->GetName() << ") violated at position " << position << "."; } void QmitkUSNavigationStepMarkerIntervention::ClearZones() { ui->riskStructuresRangeWidget->ClearZones(); // remove all reached target nodes from the data storage and clear the list mitk::DataStorage::Pointer dataStorage = this->GetDataStorage(); for (QVector::iterator it = m_ReachedTargetsNodes.begin(); it != m_ReachedTargetsNodes.end(); ++it) { if (it->IsNotNull()) { dataStorage->Remove(*it); } } m_ReachedTargetsNodes.clear(); } void QmitkUSNavigationStepMarkerIntervention::UpdateTargetCoordinates(mitk::DataNode *dataNode) { m_NodeDisplacementFilter->ResetNodes(); for (QVector>::iterator it = m_ReachedTargetsNodes.begin(); it != m_ReachedTargetsNodes.end(); ++it) { if (it->IsNotNull() && (*it)->GetData() != 0) { m_NodeDisplacementFilter->AddNode(*it); } } mitk::BaseData *baseData = dataNode->GetData(); if (!baseData) { mitkThrow() << "Data of the data node must not be null."; } mitk::BaseGeometry::Pointer geometry = baseData->GetGeometry(); if (geometry.IsNull()) { mitkThrow() << "Geometry of the data node must not be null."; } m_TargetUpdateFilter->SetControlNode(m_CurrentTargetIndex - 1, dataNode); if (m_PlannedTargetsNodes.size() > m_CurrentTargetIndex - 1) { m_PlannedTargetsNodes.at(m_CurrentTargetIndex - 1)->SetVisibility(false); } MITK_INFO("QmitkUSAbstractNavigationStep") ("QmitkUSNavigationStepMarkerIntervention") << "Target " << m_CurrentTargetIndex << " reached at position " << geometry->GetOrigin(); this->CalculateTargetPlacementQuality(); } void QmitkUSNavigationStepMarkerIntervention::UpdateBodyMarkerStatus(mitk::NavigationData::Pointer bodyMarker) { if (bodyMarker.IsNull()) { MITK_ERROR("QmitkUSAbstractNavigationStep") ("QmitkUSNavigationStepMarkerIntervention") << "Current Navigation Data for body marker of Combined Modality must not be null."; mitkThrow() << "Current Navigation Data for body marker of Combined Modality must not be null."; } bool valid = bodyMarker->IsDataValid(); // update body marker status label if (valid) { ui->bodyMarkerTrackingStatusLabel->setStyleSheet( "background-color: #8bff8b; margin-right: 1em; margin-left: 1em; border: 1px solid grey"); ui->bodyMarkerTrackingStatusLabel->setText("Body marker is inside the tracking volume."); } else { ui->bodyMarkerTrackingStatusLabel->setStyleSheet( "background-color: #ff7878; margin-right: 1em; margin-left: 1em; border: 1px solid grey"); ui->bodyMarkerTrackingStatusLabel->setText("Body marker is not inside the tracking volume."); } ui->targetStructuresRangeGroupBox->setEnabled(valid); ui->riskStructuresRangeGroupBox->setEnabled(valid); } void QmitkUSNavigationStepMarkerIntervention::GenerateTargetColorLookupTable() { vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetHueRange(0.0, 0.33); lookupTable->SetSaturationRange(1.0, 1.0); lookupTable->SetValueRange(1.0, 1.0); lookupTable->SetTableRange(0.0, 1.0); lookupTable->Build(); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetVtkLookupTable(lookupTable); m_TargetColorLookupTableProperty = mitk::LookupTableProperty::New(lut); } void QmitkUSNavigationStepMarkerIntervention::UpdateTargetColors() { if (m_TargetNode.IsNull()) { return; } m_TargetNode->SetColor(1, 1, 1); mitk::BaseData *targetNodeData = m_TargetNode->GetData(); if (targetNodeData == 0) { return; } mitk::Surface::Pointer targetNodeSurface = dynamic_cast(targetNodeData); vtkSmartPointer targetNodeSurfaceVtk = targetNodeSurface->GetVtkPolyData(); vtkPointData *targetPointData = targetNodeSurface->GetVtkPolyData()->GetPointData(); vtkFloatArray *scalars = dynamic_cast(targetPointData->GetScalars("USNavigation::Occlusion")); vtkFloatArray *targetScoreScalars; if (m_ShowPlanningColors) { targetScoreScalars = dynamic_cast(targetPointData->GetScalars("USNavigation::PlanningScalars")); } else { targetScoreScalars = dynamic_cast(targetPointData->GetScalars("USNavigation::ReachedTargetScores")); } if (!scalars || !targetScoreScalars) { return; } unsigned int numberOfTupels = scalars->GetNumberOfTuples(); vtkSmartPointer colors = vtkSmartPointer::New(); colors->SetNumberOfComponents(1); colors->SetNumberOfTuples(numberOfTupels); colors->SetName("Colors"); double color, intersection, markerScore; for (unsigned int n = 0; n < numberOfTupels; n++) { scalars->GetTuple(n, &intersection); targetScoreScalars->GetTuple(n, &markerScore); if (intersection > 0) { color = 0; } else { color = markerScore; } colors->SetTuple(n, &color); } if (numberOfTupels > 0) { targetNodeSurfaceVtk->GetPointData()->SetScalars(colors); targetNodeSurfaceVtk->GetPointData()->Update(); } } void QmitkUSNavigationStepMarkerIntervention::UpdateTargetScore() { if (m_NeedleProjectionFilter->GetProjection()->GetSize() != 2) { return; } vtkSmartPointer targetSurfaceVtk = m_TargetSurface->GetVtkPolyData(); m_TargetIntersectionFilter->SetTargetSurface(m_TargetSurface); m_TargetIntersectionFilter->SetLine(m_NeedleProjectionFilter->GetProjection()); m_TargetIntersectionFilter->CalculateIntersection(); if (m_TargetIntersectionFilter->GetIsIntersecting()) { vtkFloatArray *scalars = dynamic_cast(targetSurfaceVtk->GetPointData()->GetScalars("USNavigation::ReachedTargetScores")); double score; scalars->GetTuple(m_TargetIntersectionFilter->GetIntersectionNearestSurfacePointId(), &score); double color[3]; m_TargetColorLookupTableProperty->GetLookupTable()->GetVtkLookupTable()->GetColor(score, color); float colorF[3]; colorF[0] = color[0]; colorF[1] = color[1]; colorF[2] = color[2]; m_TargetProgressBar->SetColor(colorF); m_TargetProgressBar->SetBorderColor(colorF); m_TargetProgressBar->setValue(m_TargetIntersectionFilter->GetDistanceToIntersection()); if (m_PlannedTargetProgressBar) { vtkFloatArray *scalars = dynamic_cast(targetSurfaceVtk->GetPointData()->GetScalars("USNavigation::PlanningScalars")); if (scalars) { double score; scalars->GetTuple(m_TargetIntersectionFilter->GetIntersectionNearestSurfacePointId(), &score); double color[3]; m_TargetColorLookupTableProperty->GetLookupTable()->GetVtkLookupTable()->GetColor(score, color); float colorF[3]; colorF[0] = color[0]; colorF[1] = color[1]; colorF[2] = color[2]; m_PlannedTargetProgressBar->SetColor(colorF); m_PlannedTargetProgressBar->SetBorderColor(colorF); m_PlannedTargetProgressBar->SetTextFormatValid("Planned Target: %1 mm"); mitk::Point3D intersectionPoint = m_TargetIntersectionFilter->GetIntersectionPoint(); mitk::ScalarType minDistance = -1; for (QVector>::iterator it = m_PlannedTargetsNodes.begin(); it != m_PlannedTargetsNodes.end(); ++it) { mitk::ScalarType distance = intersectionPoint.EuclideanDistanceTo((*it)->GetData()->GetGeometry()->GetOrigin()); if (minDistance < 0 || distance < minDistance) { minDistance = distance; } } m_PlannedTargetProgressBar->setValue(minDistance); } } } else { m_TargetProgressBar->setValueInvalid(); } } void QmitkUSNavigationStepMarkerIntervention::UpdateTargetProgressDisplay() { QString description; if (m_CurrentTargetIndex >= static_cast(m_NumberOfTargets)) { description = "All Targets Reached"; if (m_TargetProgressBar) { m_TargetProgressBar->hide(); } } else { description = QString("Distance to Target ") + QString::number(m_CurrentTargetIndex + 1) + QString(" of ") + QString::number(m_NumberOfTargets); if (m_TargetProgressBar) { m_TargetProgressBar->show(); } } ui->targetStructuresRangeGroupBox->setTitle(description); } void QmitkUSNavigationStepMarkerIntervention::UpdatePlannedTargetProgressDisplay() { // make sure that the needle projection consists of two points if (m_NeedleProjectionFilter->GetProjection()->GetSize() != 2) { return; } vtkSmartPointer targetSurfaceVtk = m_TargetSurface->GetVtkPolyData(); m_TargetIntersectionFilter->SetTargetSurface(m_TargetSurface); m_TargetIntersectionFilter->SetLine(m_NeedleProjectionFilter->GetProjection()); m_TargetIntersectionFilter->CalculateIntersection(); // update target progress bar according to the color of the intersection // point on the target surface and the distance to the intersection if (m_TargetIntersectionFilter->GetIsIntersecting()) { vtkFloatArray *scalars = dynamic_cast(targetSurfaceVtk->GetPointData()->GetScalars("Colors")); double score; scalars->GetTuple(m_TargetIntersectionFilter->GetIntersectionNearestSurfacePointId(), &score); double color[3]; m_TargetColorLookupTableProperty->GetLookupTable()->GetVtkLookupTable()->GetColor(score, color); float colorF[3]; colorF[0] = color[0]; colorF[1] = color[1]; colorF[2] = color[2]; m_TargetProgressBar->SetColor(colorF); m_TargetProgressBar->SetBorderColor(colorF); m_TargetProgressBar->setValue(m_TargetIntersectionFilter->GetDistanceToIntersection()); } else { float red[3] = {0.6f, 0.0f, 0.0f}; m_TargetProgressBar->SetBorderColor(red); m_TargetProgressBar->setValueInvalid(); } } void QmitkUSNavigationStepMarkerIntervention::UpdateTargetViolationStatus() { // transform vtk polydata according to mitk geometry vtkSmartPointer transformFilter = vtkSmartPointer::New(); transformFilter->SetInputData(0, m_TargetSurface->GetVtkPolyData()); transformFilter->SetTransform(m_TargetSurface->GetGeometry()->GetVtkTransform()); transformFilter->Update(); vtkSmartPointer enclosedPoints = vtkSmartPointer::New(); enclosedPoints->Initialize(transformFilter->GetOutput()); mitk::Point3D needleTip = m_NeedleProjectionFilter->GetProjection()->GetPoint(0); // show warning if the needle tip is inside the target surface if (enclosedPoints->IsInsideSurface(needleTip[0], needleTip[1], needleTip[2])) { if (!m_TargetStructureWarnOverlay->IsVisible(NULL)) { m_TargetStructureWarnOverlay->SetVisibility(true); mitk::DataNode::Pointer targetViolationResult = mitk::DataNode::New(); targetViolationResult->SetName("TargetViolation"); targetViolationResult->SetProperty("USNavigation::TargetViolationPoint", mitk::Point3dProperty::New(needleTip)); emit SignalIntermediateResult(targetViolationResult); } MITK_INFO("QmitkUSAbstractNavigationStep") ("QmitkUSNavigationStepMarkerIntervention") << "Target surface violated at " << needleTip << "."; } else { m_TargetStructureWarnOverlay->SetVisibility(false); } } void QmitkUSNavigationStepMarkerIntervention::CalculateTargetPlacementQuality() { // clear quality display if there aren't all targets reached if (m_ReachedTargetsNodes.size() != static_cast(m_NumberOfTargets)) { ui->placementQualityGroupBox->setEnabled(false); ui->angleDifferenceValue->setText(""); ui->centersOfMassValue->setText(""); return; } ui->placementQualityGroupBox->setEnabled(true); mitk::Surface::Pointer targetSurface = dynamic_cast(m_TargetNode->GetData()); if (targetSurface.IsNull()) { mitkThrow() << "Target surface must not be null."; } m_PlacementQualityCalculator->SetTargetSurface(targetSurface); mitk::PointSet::Pointer targetPointSet = mitk::PointSet::New(); // copy the origins of all reached target nodes into a point set // for the quality calculator mitk::PointSet::PointIdentifier n = 0; for (QVector>::iterator it = m_ReachedTargetsNodes.begin(); it != m_ReachedTargetsNodes.end(); ++it) { targetPointSet->InsertPoint(n++, (*it)->GetData()->GetGeometry()->GetOrigin()); } m_PlacementQualityCalculator->SetTargetPoints(targetPointSet); m_PlacementQualityCalculator->Update(); double centersOfMassDistance = m_PlacementQualityCalculator->GetCentersOfMassDistance(); ui->centersOfMassValue->setText(QString::number(centersOfMassDistance, 103, 2) + " mm"); double meanAnglesDifference = m_PlacementQualityCalculator->GetMeanAngleDifference(); ui->angleDifferenceValue->setText(QString::number(meanAnglesDifference, 103, 2) + QString::fromLatin1(" °")); // create an intermediate result of the placement quality mitk::DataNode::Pointer placementQualityResult = mitk::DataNode::New(); placementQualityResult->SetName("PlacementQuality"); placementQualityResult->SetFloatProperty("USNavigation::CentersOfMassDistance", centersOfMassDistance); placementQualityResult->SetFloatProperty("USNavigation::MeanAngleDifference", meanAnglesDifference); placementQualityResult->SetProperty( "USNavigation::AngleDifferences", mitk::GenericProperty::New(m_PlacementQualityCalculator->GetAngleDifferences())); if (m_PlannedTargetsNodes.size() == static_cast(m_NumberOfTargets)) { mitk::VnlVector reachedPlannedDifferences; double reachedPlannedDifferencesSum = 0; double reachedPlannedDifferencesMax = 0; reachedPlannedDifferences.set_size(m_NumberOfTargets); // get sum and maximum of the planning / reality differences for (unsigned int n = 0; n < m_NumberOfTargets; ++n) { mitk::ScalarType distance = m_PlannedTargetsNodes.at(n)->GetData()->GetGeometry()->GetOrigin().EuclideanDistanceTo( m_ReachedTargetsNodes.at(n)->GetData()->GetGeometry()->GetOrigin()); reachedPlannedDifferences.put(n, distance); reachedPlannedDifferencesSum += distance; if (distance > reachedPlannedDifferencesMax) { reachedPlannedDifferencesMax = distance; } } // add distances between planning and reality to the quality intermediate result placementQualityResult->SetProperty("USNavigation::PlanningRealityDistances", mitk::GenericProperty::New(reachedPlannedDifferences)); placementQualityResult->SetProperty( "USNavigation::MeanPlanningRealityDistance", mitk::DoubleProperty::New(reachedPlannedDifferencesSum / static_cast(m_NumberOfTargets))); placementQualityResult->SetProperty("USNavigation::MaximumPlanningRealityDistance", mitk::DoubleProperty::New(reachedPlannedDifferencesMax)); } emit SignalIntermediateResult(placementQualityResult); } void QmitkUSNavigationStepMarkerIntervention::UpdateSensorsNames() { - mitk::USCombinedModality::Pointer combinedModality = this->GetCombinedModality(false); + mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->GetCombinedModality(false); if (combinedModality.IsNull()) { return; } mitk::NavigationDataSource::Pointer navigationDataSource = combinedModality->GetNavigationDataSource(); if (navigationDataSource.IsNull()) { return; } if (!m_NeedleSensorName.empty()) { try { m_NeedleSensorIndex = navigationDataSource->GetOutputIndex(m_NeedleSensorName); } catch (const std::exception &e) { MITK_WARN("QmitkUSAbstractNavigationStep") ("QmitkUSNavigationStepPlacementPlanning") << "Cannot get index for needle sensor name: " << e.what(); } } if (this->GetNavigationStepState() >= QmitkUSAbstractNavigationStep::State_Active) { m_NeedleProjectionFilter->SelectInput(m_NeedleSensorIndex); } if (!m_ReferenceSensorName.empty()) { try { m_ReferenceSensorIndex = navigationDataSource->GetOutputIndex(m_ReferenceSensorName); } catch (const std::exception &e) { MITK_WARN("QmitkUSAbstractNavigationStep") ("QmitkUSNavigationStepPlacementPlanning") << "Cannot get index for reference sensor name: " << e.what(); } } if (this->GetNavigationStepState() >= QmitkUSAbstractNavigationStep::State_Active) { m_NodeDisplacementFilter->SelectInput(m_ReferenceSensorIndex); } ui->freezeImageButton->SetCombinedModality(combinedModality, m_ReferenceSensorIndex); } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPlacementPlanning.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPlacementPlanning.cpp index 4554922d1d..a41c4db55a 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPlacementPlanning.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPlacementPlanning.cpp @@ -1,817 +1,817 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkUSNavigationStepPlacementPlanning.h" #include "ui_QmitkUSNavigationStepPlacementPlanning.h" #include "../Interactors/mitkUSPointMarkInteractor.h" #include "../mitkUSTargetPlacementQualityCalculator.h" #include "mitkNeedleProjectionFilter.h" #include "mitkNodeDisplacementFilter.h" #include "usModuleRegistry.h" #include "../Filter/mitkUSNavigationTargetIntersectionFilter.h" #include "../Filter/mitkUSNavigationTargetUpdateFilter.h" #include "../QmitkUSNavigationMarkerPlacement.h" #include "mitkLookupTableProperty.h" #include "mitkSurface.h" #include #include "mitkLayoutAnnotationRenderer.h" #include "mitkTextAnnotation3D.h" #include "vtkFloatArray.h" #include "vtkLookupTable.h" #include "vtkPointData.h" #include "vtkPolyData.h" #include "vtkSmartPointer.h" #include "vtkLineSource.h" #include "vtkSphereSource.h" #include "vtkCenterOfMass.h" #include "vtkLinearTransform.h" #include "vtkPoints.h" #include "vtkTransformPolyDataFilter.h" #include "vtkUnstructuredGrid.h" #include "vtkMath.h" QmitkUSNavigationStepPlacementPlanning::QmitkUSNavigationStepPlacementPlanning(QWidget *parent) : QmitkUSAbstractNavigationStep(parent), m_NumberOfTargets(0), m_CurrentTargetIndex(0), m_BodyMarkerValid(false), m_PointMarkInteractor(mitk::USPointMarkInteractor::New()), m_TargetUpdateFilter(mitk::USNavigationTargetUpdateFilter::New()), m_NodeDisplacementFilter(mitk::NodeDisplacementFilter::New()), m_NeedleProjectionFilter(mitk::NeedleProjectionFilter::New()), m_TargetIntersectionFilter(mitk::USNavigationTargetIntersectionFilter::New()), m_PlacementQualityCalculator(mitk::USTargetPlacementQualityCalculator::New()), m_ReferenceSensorIndex(1), m_NeedleSensorIndex(0), m_ListenerTargetCoordinatesChanged(this, &QmitkUSNavigationStepPlacementPlanning::UpdateTargetCoordinates), ui(new Ui::QmitkUSNavigationStepPlacementPlanning) { ui->setupUi(this); connect(ui->freezeImageButton, SIGNAL(SignalFreezed(bool)), this, SLOT(OnFreeze(bool))); m_TargetUpdateFilter->SetScalarArrayIdentifier("USNavigation::PlanningPlacement"); this->GenerateTargetColorLookupTable(); } QmitkUSNavigationStepPlacementPlanning::~QmitkUSNavigationStepPlacementPlanning() { delete ui; } bool QmitkUSNavigationStepPlacementPlanning::OnStartStep() { // create node for needle projection mitk::DataNode::Pointer node = this->GetNamedDerivedNodeAndCreate("Needle Path", QmitkUSAbstractNavigationStep::DATANAME_BASENODE); node->SetData(m_NeedleProjectionFilter->GetProjection()); node->SetBoolProperty("show contour", true); // make sure that the targets node exist in the data storage this->GetNamedDerivedNodeAndCreate(QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS, QmitkUSAbstractNavigationStep::DATANAME_BASENODE); this->GetNamedDerivedNodeAndCreate(QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS_PATHS, QmitkUSAbstractNavigationStep::DATANAME_BASENODE); // listen to event of point mark interactor m_PointMarkInteractor->CoordinatesChangedEvent.AddListener(m_ListenerTargetCoordinatesChanged); return true; } bool QmitkUSNavigationStepPlacementPlanning::OnStopStep() { // remove listener to event of point mark interactor m_PointMarkInteractor->CoordinatesChangedEvent.RemoveListener(m_ListenerTargetCoordinatesChanged); m_CurrentTargetIndex = 0; m_TargetUpdateFilter->Reset(); m_NodeDisplacementFilter->ResetNodes(); // remove the planned target nodes from the data storage mitk::DataStorage::Pointer dataStorage = this->GetDataStorage(); for (QVector>::iterator it = m_PlannedTargetNodes.begin(); it != m_PlannedTargetNodes.end(); ++it) { dataStorage->Remove(*it); } m_PlannedTargetNodes.clear(); // remove the planned target path nodes from the data storage for (QVector>::iterator it = m_PlannedNeedlePaths.begin(); it != m_PlannedNeedlePaths.end(); ++it) { dataStorage->Remove(*it); } m_PlannedNeedlePaths.clear(); // remove the targets node from the data storage mitk::DataNode::Pointer targetsNode = this->GetNamedDerivedNode(QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS, QmitkUSAbstractNavigationStep::DATANAME_BASENODE); if (targetsNode.IsNotNull()) { dataStorage->Remove(targetsNode); } // remove the target paths node from the data storage mitk::DataNode::Pointer targetPathsNode = this->GetNamedDerivedNode( QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS_PATHS, QmitkUSAbstractNavigationStep::DATANAME_BASENODE); if (targetPathsNode.IsNotNull()) { dataStorage->Remove(targetPathsNode); } // make sure that the image is no longer freezed after stopping ui->freezeImageButton->Unfreeze(); return true; } bool QmitkUSNavigationStepPlacementPlanning::OnRestartStep() { this->OnStopStep(); this->OnStartStep(); return true; } bool QmitkUSNavigationStepPlacementPlanning::OnFinishStep() { // create scalars showing the planned positions on the target surface if (!m_PlannedTargetNodes.isEmpty()) { mitk::USNavigationTargetUpdateFilter::Pointer planningSurfaceFilter = mitk::USNavigationTargetUpdateFilter::New(); planningSurfaceFilter->SetOptimalAngle(0); planningSurfaceFilter->SetScalarArrayIdentifier("USNavigation::PlanningScalars"); planningSurfaceFilter->SetUseMaximumScore(true); planningSurfaceFilter->SetTargetStructure(m_TargetNode); unsigned int n = 0; for (QVector>::iterator it = m_PlannedTargetNodes.begin(); it != m_PlannedTargetNodes.end(); ++it) { bool isSurfaceEmpty; if (((*it)->GetBoolProperty("surface_empty", isSurfaceEmpty)) && isSurfaceEmpty) { // remove node from data storage if it is not fully planned this->GetDataStorage()->Remove(*it); } else { // set origin to filter for coloring target surface (good // positions are positions near to the origin) planningSurfaceFilter->SetControlNode(n, *it); } n++; } } // make sure that the image is no longer freezed after finishing ui->freezeImageButton->Unfreeze(); return true; } bool QmitkUSNavigationStepPlacementPlanning::OnActivateStep() { emit SignalReadyForNextStep(); m_NodeDisplacementFilter->SelectInput(m_ReferenceSensorIndex); m_NeedleProjectionFilter->SelectInput(m_NeedleSensorIndex); if (m_PlannedTargetNodes.empty()) { m_CurrentTargetIndex = 0; } else { m_CurrentTargetIndex = m_PlannedTargetNodes.size() - 1; } m_TargetNode = this->GetNamedDerivedNode(QmitkUSNavigationMarkerPlacement::DATANAME_TARGETSURFACE, QmitkUSNavigationMarkerPlacement::DATANAME_TUMOUR); m_TargetNode->SetBoolProperty("visible", true); // set lookup table of tumour node m_TargetNode->SetProperty("LookupTable", m_TargetColorLookupTableProperty); m_TargetUpdateFilter->SetTargetStructure(m_TargetNode); for (QVector>::iterator it = m_PlannedTargetNodes.begin(); it != m_PlannedTargetNodes.end(); ++it) { (*it)->SetBoolProperty("visible", true); } this->UpdateTargetDescriptions(); // m_TargetUpdateFilter->UpdateTargetScores(); return true; } bool QmitkUSNavigationStepPlacementPlanning::OnDeactivateStep() { ui->freezeImageButton->Unfreeze(); return true; } void QmitkUSNavigationStepPlacementPlanning::OnUpdate() { this->UpdateTargetColors(); // get navigation data source and make sure that it is not null mitk::NavigationDataSource::Pointer navigationDataSource = this->GetCombinedModality()->GetNavigationDataSource(); if (navigationDataSource.IsNull()) { MITK_ERROR("QmitkUSAbstractNavigationStep") ("QmitkUSNavigationStepPunctuationIntervention") << "Navigation Data Source of Combined Modality must not be null."; mitkThrow() << "Navigation Data Source of Combined Modality must not be null."; } navigationDataSource->Update(); this->UpdateBodyMarkerStatus(navigationDataSource->GetOutput(m_ReferenceSensorIndex)); ui->freezeImageButton->setEnabled(m_BodyMarkerValid); mitk::PointSet::Pointer needleProjectionPointSet = m_NeedleProjectionFilter->GetProjection(); if (needleProjectionPointSet->GetSize() == 2) { m_TargetIntersectionFilter->SetTargetSurface(dynamic_cast(m_TargetNode->GetData())); m_TargetIntersectionFilter->SetLine(needleProjectionPointSet); m_TargetIntersectionFilter->CalculateIntersection(); if (m_TargetIntersectionFilter->GetIsIntersecting()) { // only enable button if body marker is in the tracking volume, too ui->placeTargetButton->setEnabled(m_BodyMarkerValid); ui->placeTargetButton->setToolTip(""); if (m_PlannedTargetNodes.size() == m_NumberOfTargets - 1) { mitk::PointSet::Pointer targetPointSet = mitk::PointSet::New(); mitk::PointSet::PointIdentifier n = 0; for (QVector>::iterator it = m_PlannedTargetNodes.begin(); it != m_PlannedTargetNodes.end(); ++it) { targetPointSet->InsertPoint(n++, (*it)->GetData()->GetGeometry()->GetOrigin()); } targetPointSet->InsertPoint(n, m_TargetIntersectionFilter->GetIntersectionPoint()); this->CalculatePlanningQuality(dynamic_cast(m_TargetNode->GetData()), targetPointSet); } } else { ui->placeTargetButton->setEnabled(false); ui->placeTargetButton->setToolTip( "Target cannot be placed as the needle path is not intersecting the target surface."); // no not show planning quality if not all nodes are planned for now // and there is no needle path intersection if (m_PlannedTargetNodes.size() < m_NumberOfTargets) { ui->angleDifferenceValue->setText(""); ui->centersOfMassValue->setText(""); } } } } void QmitkUSNavigationStepPlacementPlanning::OnSettingsChanged(const itk::SmartPointer settingsNode) { int numberOfTargets; if (settingsNode->GetIntProperty("settings.number-of-targets", numberOfTargets)) { m_NumberOfTargets = numberOfTargets; m_TargetUpdateFilter->SetNumberOfTargets(numberOfTargets); m_PlacementQualityCalculator->SetOptimalAngle(m_TargetUpdateFilter->GetOptimalAngle()); } std::string referenceSensorName; if (settingsNode->GetStringProperty("settings.reference-name-selected", referenceSensorName)) { m_ReferenceSensorName = referenceSensorName; } std::string needleSensorName; if (settingsNode->GetStringProperty("settings.needle-name-selected", needleSensorName)) { m_NeedleSensorName = needleSensorName; } this->UpdateSensorsNames(); } QString QmitkUSNavigationStepPlacementPlanning::GetTitle() { return "Placement Planning"; } QmitkUSAbstractNavigationStep::FilterVector QmitkUSNavigationStepPlacementPlanning::GetFilter() { FilterVector filterVector; filterVector.push_back(m_NodeDisplacementFilter.GetPointer()); filterVector.push_back(m_NeedleProjectionFilter.GetPointer()); return filterVector; } void QmitkUSNavigationStepPlacementPlanning::OnSetCombinedModality() { - mitk::USCombinedModality::Pointer combinedModality = this->GetCombinedModality(false); + mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->GetCombinedModality(false); if (combinedModality.IsNotNull()) { mitk::AffineTransform3D::Pointer calibration = combinedModality->GetCalibration(); if (calibration.IsNotNull()) { m_NeedleProjectionFilter->SetTargetPlane(calibration); } } ui->freezeImageButton->SetCombinedModality(combinedModality, m_ReferenceSensorIndex); this->UpdateSensorsNames(); } void QmitkUSNavigationStepPlacementPlanning::OnFreeze(bool freeze) { if (freeze) - this->GetCombinedModality()->SetIsFreezed(true); + this->GetCombinedModality()->GetUltrasoundDevice()->SetIsFreezed(true); if (freeze) { // load state machine and event config for data interactor m_PointMarkInteractor->LoadStateMachine("USPointMarkInteractions.xml", us::ModuleRegistry::GetModule("MitkUS")); m_PointMarkInteractor->SetEventConfig("globalConfig.xml"); this->CreateTargetNodesIfNecessary(); m_PointMarkInteractor->SetDataNode(m_PlannedTargetNodes.at(m_CurrentTargetIndex)); } else { m_PointMarkInteractor->SetDataNode(0); } if (!freeze) - this->GetCombinedModality()->SetIsFreezed(false); + this->GetCombinedModality()->GetUltrasoundDevice()->SetIsFreezed(false); } void QmitkUSNavigationStepPlacementPlanning::OnPlaceTargetButtonClicked() { this->CreateTargetNodesIfNecessary(); mitk::DataNode::Pointer currentNode = m_PlannedTargetNodes.at(m_CurrentTargetIndex); currentNode->SetData(this->CreateSphere(5)); currentNode->SetBoolProperty("surface_empty", false); mitk::PointSet::Pointer needleProjection = m_NeedleProjectionFilter->GetProjection(); m_TargetIntersectionFilter->SetTargetSurface(dynamic_cast(m_TargetNode->GetData())); m_TargetIntersectionFilter->SetLine(m_NeedleProjectionFilter->GetProjection()); m_TargetIntersectionFilter->CalculateIntersection(); mitk::Point3D intersectionPoint = m_TargetIntersectionFilter->GetIntersectionPoint(); currentNode->GetData()->GetGeometry()->SetOrigin(intersectionPoint); m_TargetUpdateFilter->SetControlNode(m_CurrentTargetIndex, currentNode); mitk::PointSet::Pointer plannedPath = mitk::PointSet::New(); m_PlannedNeedlePaths.at(m_CurrentTargetIndex)->SetData(plannedPath); plannedPath->SetPoint(0, needleProjection->GetPoint(0)); plannedPath->SetPoint(1, intersectionPoint); if (m_CurrentTargetIndex < m_NumberOfTargets - 1) { this->OnGoToNextTarget(); } else { this->UpdateTargetDescriptions(); } this->ReinitNodeDisplacementFilter(); MITK_INFO("QmitkUSAbstractNavigationStep") ("QmitkUSNavigationStepPlacementPlanning") << "Target " << m_CurrentTargetIndex + 1 << " planned at position " << intersectionPoint << "."; } void QmitkUSNavigationStepPlacementPlanning::OnGoToPreviousTarget() { if (m_CurrentTargetIndex < 1) { mitkThrow() << "Cannot go to previous target as current target is first target."; } m_CurrentTargetIndex--; this->UpdateTargetDescriptions(); } void QmitkUSNavigationStepPlacementPlanning::OnGoToNextTarget() { m_CurrentTargetIndex++; this->UpdateTargetDescriptions(); } void QmitkUSNavigationStepPlacementPlanning::OnRemoveCurrentTargetClicked() { if (m_CurrentTargetIndex >= m_PlannedTargetNodes.size()) { MITK_WARN << "Cannot remove current target as there aren't as much planned target nodes."; return; } this->GetDataStorage()->Remove(m_PlannedTargetNodes.at(m_CurrentTargetIndex)); m_PlannedTargetNodes.remove(m_CurrentTargetIndex); this->GetDataStorage()->Remove(m_PlannedNeedlePaths.at(m_CurrentTargetIndex)); m_PlannedNeedlePaths.remove(m_CurrentTargetIndex); this->ReinitNodeDisplacementFilter(); for (int n = 0; n < m_PlannedTargetNodes.size(); ++n) { // set name of the target node according to its new index m_PlannedTargetNodes.at(n)->SetName( QString("Target %1").arg(n + 1, m_NumberOfTargets / 10 + 1, 10, QLatin1Char('0')).toStdString()); m_PlannedNeedlePaths.at(n)->SetName( QString("Target Path %1").arg(n + 1, m_NumberOfTargets / 10 + 1, 10, QLatin1Char('0')).toStdString()); } m_TargetUpdateFilter->RemovePositionOfTarget(m_CurrentTargetIndex); m_CurrentTargetIndex = m_PlannedTargetNodes.size(); this->UpdateTargetDescriptions(); MITK_INFO("QmitkUSAbstractNavigationStep") ("QmitkUSNavigationStepPlacementPlanning") << "Planned target " << m_CurrentTargetIndex + 1 << " removed."; } void QmitkUSNavigationStepPlacementPlanning::CreateTargetNodesIfNecessary() { mitk::DataStorage::Pointer dataStorage = this->GetDataStorage(); while (m_PlannedTargetNodes.size() <= m_CurrentTargetIndex) { QString targetNumber = QString("%1").arg(m_PlannedTargetNodes.size() + 1, m_NumberOfTargets / 10 + 1, 10, QLatin1Char('0')); mitk::DataNode::Pointer targetNode = this->GetNamedDerivedNodeAndCreate( (QString("Target ") + targetNumber).toStdString().c_str(), QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS); targetNode->SetOpacity(0.5); targetNode->SetBoolProperty("surface_empty", true); targetNode->SetData(mitk::Surface::New()); m_PlannedTargetNodes.push_back(targetNode); mitk::DataNode::Pointer targetPathNode = this->GetNamedDerivedNodeAndCreate((QString("Target Path ") + targetNumber).toStdString().c_str(), QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS_PATHS); targetPathNode->SetOpacity(0.5); targetPathNode->SetColor(1, 1, 1); targetPathNode->SetColor(1, 1, 1, nullptr, "contourcolor"); targetPathNode->SetBoolProperty("show contour", true); m_PlannedNeedlePaths.push_back(targetPathNode); mitk::Surface::Pointer pathSurface = mitk::Surface::New(); targetPathNode->SetData(pathSurface); } } void QmitkUSNavigationStepPlacementPlanning::UpdateTargetCoordinates(mitk::DataNode *dataNode) { bool surfaceEmpty; if (dataNode->GetBoolProperty("surface_empty", surfaceEmpty) && surfaceEmpty) { mitk::Point3D origin = dataNode->GetData()->GetGeometry()->GetOrigin(); dataNode->SetData(this->CreateSphere(5)); dataNode->SetBoolProperty("surface_empty", false); dataNode->GetData()->GetGeometry()->SetOrigin(origin); } this->ReinitNodeDisplacementFilter(); mitk::BaseData *baseData = dataNode->GetData(); if (!baseData) { mitkThrow() << "Data of the data node must not be null."; } mitk::BaseGeometry::Pointer geometry = baseData->GetGeometry(); if (geometry.IsNull()) { mitkThrow() << "Geometry of the data node must not be null."; } m_TargetUpdateFilter->SetControlNode(m_CurrentTargetIndex, dataNode); MITK_INFO("QmitkUSAbstractNavigationStep") ("QmitkUSNavigationStepPlacementPlanning") << "Target " << m_CurrentTargetIndex + 1 << " planned at position " << geometry->GetOrigin() << "."; if (ui->freezeImageButton->isChecked()) { ui->freezeImageButton->Unfreeze(); if (m_CurrentTargetIndex < m_NumberOfTargets - 1) { this->OnGoToNextTarget(); } } this->UpdateTargetDescriptions(); } void QmitkUSNavigationStepPlacementPlanning::UpdateTargetColors() { if (m_TargetNode.IsNull()) { return; } m_TargetNode->SetColor(1, 1, 1); mitk::BaseData *targetNodeData = m_TargetNode->GetData(); if (targetNodeData == 0) { return; } mitk::Surface::Pointer targetNodeSurface = dynamic_cast(targetNodeData); vtkSmartPointer targetNodeSurfaceVtk = targetNodeSurface->GetVtkPolyData(); vtkFloatArray *targetScoreScalars = dynamic_cast( targetNodeSurface->GetVtkPolyData()->GetPointData()->GetScalars("USNavigation::PlanningPlacement")); if (!targetScoreScalars) { return; } unsigned int numberOfTupels = targetScoreScalars->GetNumberOfTuples(); vtkSmartPointer colors = vtkSmartPointer::New(); colors->SetNumberOfComponents(1); colors->SetNumberOfTuples(numberOfTupels); colors->SetName("Colors"); double markerScore; for (unsigned int n = 0; n < numberOfTupels; n++) { targetScoreScalars->GetTuple(n, &markerScore); colors->SetTuple(n, &markerScore); } if (numberOfTupels > 0) { targetNodeSurfaceVtk->GetPointData()->SetScalars(colors); targetNodeSurfaceVtk->GetPointData()->Update(); } } void QmitkUSNavigationStepPlacementPlanning::UpdateTargetDescriptions() { ui->previousButton->setEnabled(m_CurrentTargetIndex > 0); ui->nextButton->setEnabled(m_CurrentTargetIndex + 1 < m_PlannedTargetNodes.size()); ui->removeButton->setEnabled(m_PlannedTargetNodes.size() > 0); ui->currentTargetLabel->setText( QString("Planning Target %1 of %2").arg(m_CurrentTargetIndex + 1).arg(m_NumberOfTargets)); ui->removeButton->setEnabled(m_CurrentTargetIndex < m_PlannedTargetNodes.size()); this->CalculatePlanningQuality(); } void QmitkUSNavigationStepPlacementPlanning::GenerateTargetColorLookupTable() { vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetHueRange(0.0, 0.27); lookupTable->SetSaturationRange(1.0, 1.0); lookupTable->SetValueRange(1.0, 1.0); lookupTable->SetTableRange(0.0, 1.0); lookupTable->Build(); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetVtkLookupTable(lookupTable); m_TargetColorLookupTableProperty = mitk::LookupTableProperty::New(lut); } void QmitkUSNavigationStepPlacementPlanning::ReinitNodeDisplacementFilter() { m_NodeDisplacementFilter->ResetNodes(); for (QVector>::iterator it = m_PlannedTargetNodes.begin(); it != m_PlannedTargetNodes.end(); ++it) { if (it->IsNotNull() && (*it)->GetData() != 0) { m_NodeDisplacementFilter->AddNode(*it); } } for (QVector>::iterator it = m_PlannedNeedlePaths.begin(); it != m_PlannedNeedlePaths.end(); ++it) { if (it->IsNotNull() && (*it)->GetData() != 0) { m_NodeDisplacementFilter->AddNode(*it); } } } void QmitkUSNavigationStepPlacementPlanning::CalculatePlanningQuality() { if (m_PlannedTargetNodes.size() != m_NumberOfTargets) { ui->angleDifferenceLabel->setEnabled(false); ui->centersOfMassLabel->setEnabled(false); ui->allTargetsPlannedLabel->setEnabled(false); ui->angleDifferenceValue->setText(""); ui->centersOfMassValue->setText(""); return; } ui->angleDifferenceLabel->setEnabled(true); ui->centersOfMassLabel->setEnabled(true); ui->allTargetsPlannedLabel->setEnabled(true); mitk::PointSet::Pointer targetPointSet = mitk::PointSet::New(); mitk::PointSet::PointIdentifier n = 0; for (QVector>::iterator it = m_PlannedTargetNodes.begin(); it != m_PlannedTargetNodes.end(); ++it) { targetPointSet->InsertPoint(n++, (*it)->GetData()->GetGeometry()->GetOrigin()); } mitk::DataNode::Pointer planningQualityResult = this->CalculatePlanningQuality(dynamic_cast(m_TargetNode->GetData()), targetPointSet); emit SignalIntermediateResult(planningQualityResult); } mitk::DataNode::Pointer QmitkUSNavigationStepPlacementPlanning::CalculatePlanningQuality( mitk::Surface::Pointer targetSurface, mitk::PointSet::Pointer targetPoints) { if (targetSurface.IsNull()) { mitkThrow() << "Target surface must not be null."; } m_PlacementQualityCalculator->SetTargetSurface(targetSurface); m_PlacementQualityCalculator->SetTargetPoints(targetPoints); m_PlacementQualityCalculator->Update(); mitk::DataNode::Pointer planningQualityResult = mitk::DataNode::New(); planningQualityResult->SetName("PlanningQuality"); double centersOfMassDistance = m_PlacementQualityCalculator->GetCentersOfMassDistance(); ui->centersOfMassValue->setText(QString::number(centersOfMassDistance, 103, 2) + " mm"); planningQualityResult->SetFloatProperty("USNavigation::CentersOfMassDistance", centersOfMassDistance); if (m_PlannedTargetNodes.size() > 1) { double meanAnglesDifference = m_PlacementQualityCalculator->GetMeanAngleDifference(); ui->angleDifferenceValue->setText(QString::number(meanAnglesDifference, 103, 2) + QString::fromLatin1(" °")); planningQualityResult->SetFloatProperty("USNavigation::MeanAngleDifference", meanAnglesDifference); planningQualityResult->SetProperty( "USNavigation::AngleDifferences", mitk::GenericProperty::New(m_PlacementQualityCalculator->GetAngleDifferences())); } else { ui->angleDifferenceValue->setText("not valid for one point"); } return planningQualityResult; } itk::SmartPointer QmitkUSNavigationStepPlacementPlanning::CreateSphere(float) { mitk::Surface::Pointer surface = mitk::Surface::New(); // create a vtk sphere with fixed radius vtkSphereSource *vtkData = vtkSphereSource::New(); vtkData->SetRadius(5); vtkData->SetCenter(0, 0, 0); vtkData->Update(); surface->SetVtkPolyData(vtkData->GetOutput()); vtkData->Delete(); return surface; } void QmitkUSNavigationStepPlacementPlanning::UpdateBodyMarkerStatus(mitk::NavigationData::Pointer bodyMarker) { if (bodyMarker.IsNull()) { MITK_ERROR("QmitkUSAbstractNavigationStep") ("QmitkUSNavigationStepPunctuationIntervention") << "Current Navigation Data for body marker of Combined Modality must not be null."; mitkThrow() << "Current Navigation Data for body marker of Combined Modality must not be null."; } m_BodyMarkerValid = bodyMarker->IsDataValid(); // update body marker status label if (m_BodyMarkerValid) { ui->bodyMarkerTrackingStatusLabel->setStyleSheet( "background-color: #8bff8b; margin-right: 1em; margin-left: 1em; border: 1px solid grey"); ui->bodyMarkerTrackingStatusLabel->setText("Body marker is inside the tracking volume."); } else { ui->bodyMarkerTrackingStatusLabel->setStyleSheet( "background-color: #ff7878; margin-right: 1em; margin-left: 1em; border: 1px solid grey"); ui->bodyMarkerTrackingStatusLabel->setText("Body marker is not inside the tracking volume."); } } void QmitkUSNavigationStepPlacementPlanning::UpdateSensorsNames() { - mitk::USCombinedModality::Pointer combinedModality = this->GetCombinedModality(false); + mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->GetCombinedModality(false); if (combinedModality.IsNull()) { return; } mitk::NavigationDataSource::Pointer navigationDataSource = combinedModality->GetNavigationDataSource(); if (navigationDataSource.IsNull()) { return; } if (!m_NeedleSensorName.empty()) { try { m_NeedleSensorIndex = navigationDataSource->GetOutputIndex(m_NeedleSensorName); } catch (const std::exception &e) { MITK_WARN("QmitkUSAbstractNavigationStep") ("QmitkUSNavigationStepPlacementPlanning") << "Cannot get index for needle sensor name: " << e.what(); } } if (this->GetNavigationStepState() >= QmitkUSAbstractNavigationStep::State_Active) { m_NeedleProjectionFilter->SelectInput(m_NeedleSensorIndex); } if (!m_ReferenceSensorName.empty()) { try { m_ReferenceSensorIndex = navigationDataSource->GetOutputIndex(m_ReferenceSensorName); } catch (const std::exception &e) { MITK_WARN("QmitkUSAbstractNavigationStep") ("QmitkUSNavigationStepPlacementPlanning") << "Cannot get index for reference sensor name: " << e.what(); } } if (this->GetNavigationStepState() >= QmitkUSAbstractNavigationStep::State_Active) { m_NodeDisplacementFilter->SelectInput(m_ReferenceSensorIndex); } ui->freezeImageButton->SetCombinedModality(combinedModality, m_ReferenceSensorIndex); } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.cpp index 1fdbbb5ded..a446c8aa6a 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.cpp @@ -1,283 +1,289 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkUSNavigationStepPunctuationIntervention.h" #include "ui_QmitkUSNavigationStepPunctuationIntervention.h" #include "mitkNeedleProjectionFilter.h" #include "../Widgets/QmitkZoneProgressBar.h" #include "../QmitkUSNavigationMarkerPlacement.h" #include "usModuleRegistry.h" #include QmitkUSNavigationStepPunctuationIntervention::QmitkUSNavigationStepPunctuationIntervention(QWidget *parent) : QmitkUSAbstractNavigationStep(parent), m_Ui(new Ui::QmitkUSNavigationStepPunctuationIntervention), m_ZoneNodes(nullptr), m_NeedleProjectionFilter(mitk::NeedleProjectionFilter::New()), m_NeedleNavigationTool(mitk::NavigationTool::New()), m_OldColors(), m_SphereSource(vtkSmartPointer::New()), m_OBBTree(vtkSmartPointer::New()), m_IntersectPoints(vtkSmartPointer::New()) { m_Ui->setupUi(this); connect(m_Ui->m_AddNewAblationZone, SIGNAL(clicked()), this, SLOT(OnAddAblationZoneClicked())); connect(m_Ui->m_ShowToolAxisN, SIGNAL(stateChanged(int)), this, SLOT(OnShowToolAxisEnabled(int))); connect(m_Ui->m_EnableAblationMarking, SIGNAL(clicked()), this, SLOT(OnEnableAblationZoneMarkingClicked())); connect(m_Ui->m_AblationZoneSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(OnAblationZoneSizeSliderChanged(int))); m_Ui->m_AblationZonesBox->setVisible(false); } void QmitkUSNavigationStepPunctuationIntervention::SetNeedleMetaData(mitk::NavigationTool::Pointer needleNavigationTool) { this->m_NeedleNavigationTool = needleNavigationTool; } void QmitkUSNavigationStepPunctuationIntervention::OnEnableAblationZoneMarkingClicked() { if(m_Ui->m_EnableAblationMarking->isChecked()) m_Ui->m_AblationZonesBox->setVisible(true); else m_Ui->m_AblationZonesBox->setVisible(false); } void QmitkUSNavigationStepPunctuationIntervention::OnAblationZoneSizeSliderChanged(int size) { int id = m_Ui->m_AblationZonesList->currentRow(); if (id!=-1) {emit AblationZoneChanged(id,size);} }// void QmitkUSNavigationStepPunctuationIntervention::OnAddAblationZoneClicked() { QListWidgetItem* newItem = new QListWidgetItem("Ablation Zone (initial size: " + QString::number(m_Ui->m_AblationZoneSizeSlider->value()) + " mm)", m_Ui->m_AblationZonesList); newItem->setSelected(true); emit AddAblationZoneClicked(m_Ui->m_AblationZoneSizeSlider->value()); } QmitkUSNavigationStepPunctuationIntervention::~QmitkUSNavigationStepPunctuationIntervention() { mitk::DataStorage::Pointer dataStorage = this->GetDataStorage(false); if ( dataStorage.IsNotNull() ) { // remove needle path from data storage if it is there mitk::DataNode::Pointer node = this->GetNamedDerivedNode ("Needle Path", QmitkUSAbstractNavigationStep::DATANAME_BASENODE); if ( node.IsNotNull() ) { dataStorage->Remove(node); } } delete m_Ui; } bool QmitkUSNavigationStepPunctuationIntervention::OnStartStep() { // create node for Needle Projection mitk::DataNode::Pointer node = this->GetNamedDerivedNodeAndCreate ("Needle Path", QmitkUSAbstractNavigationStep::DATANAME_BASENODE); node->SetData(m_NeedleProjectionFilter->GetProjection()); node->SetBoolProperty("show contour", true); m_NeedleProjectionFilter->SetToolAxisForFilter(m_NeedleNavigationTool->GetToolAxis()); return true; } bool QmitkUSNavigationStepPunctuationIntervention::OnRestartStep() { return this->OnActivateStep(); } bool QmitkUSNavigationStepPunctuationIntervention::OnFinishStep() { mitk::DataNode::Pointer finishPunctionResult = mitk::DataNode::New(); finishPunctionResult->SetName("PunctionResult"); mitk::Point3D needlePos = m_NeedleProjectionFilter->GetOutput(0)->GetPosition(); mitk::Quaternion needleRot = m_NeedleProjectionFilter->GetOutput(0)->GetOrientation(); finishPunctionResult->SetProperty("USNavigation::TipPositionEnd", mitk::Point3dProperty::New(needlePos)); MITK_INFO("USNavigationLogging") << "Instrument tip at end: " <ClearZones(); mitk::DataStorage::Pointer dataStorage = this->GetDataStorage(); // add progress bars for risk zone nodes m_ZoneNodes = dataStorage->GetDerivations(dataStorage->GetNamedNode(QmitkUSNavigationMarkerPlacement::DATANAME_ZONES)); // add zones to the widgets for risk structures for (mitk::DataStorage::SetOfObjects::ConstIterator it = m_ZoneNodes->Begin(); it != m_ZoneNodes->End(); ++it) { m_Ui->riskStructuresRangeWidget->AddZone(it->Value()); float rgb[3]; it->Value()->GetColor(rgb); mitk::Color color; color.SetRed(rgb[0]); color.SetGreen(rgb[1]); color.SetBlue(rgb[2]); m_OldColors[it->Value()] = color; } m_NeedleProjectionFilter->SelectInput(0); return true; } void QmitkUSNavigationStepPunctuationIntervention::OnShowToolAxisEnabled(int enabled) { if (enabled == 0) { m_NeedleProjectionFilter->ShowToolAxis(false); } else { m_NeedleProjectionFilter->ShowToolAxis(true); } } void QmitkUSNavigationStepPunctuationIntervention::OnUpdate() { + if (this->GetCombinedModality(false).IsNull()) return; // get navigation data source and make sure that it is not null mitk::NavigationDataSource::Pointer navigationDataSource = - this->GetCombinedModality()->GetNavigationDataSource(); + this->GetCombinedModality()->GetNavigationDataSource(); + if ( navigationDataSource.IsNull() ) { + MITK_ERROR("QmitkUSAbstractNavigationStep")("QmitkUSNavigationStepPunctuationIntervention") << "Navigation Data Source of Combined Modality must not be null."; mitkThrow() << "Navigation Data Source of Combined Modality must not be null."; } // update body marker this->UpdateBodyMarkerStatus(navigationDataSource->GetOutput(1)); // update critical structures this->UpdateCriticalStructures(navigationDataSource->GetOutput(0),m_NeedleProjectionFilter->GetProjection()); + m_NeedleProjectionFilter->Update(); + //Update Distance to US image mitk::Point3D point1 = m_NeedleProjectionFilter->GetProjection()->GetPoint(0); mitk::Point3D point2 = m_NeedleProjectionFilter->GetProjection()->GetPoint(1); double distance = point1.EuclideanDistanceTo(point2); m_Ui->m_DistanceToUSPlane->setText(QString::number(distance) + " mm"); } void QmitkUSNavigationStepPunctuationIntervention::OnSettingsChanged(const itk::SmartPointer settingsNode) { if ( settingsNode.IsNull() ) { return; } } QString QmitkUSNavigationStepPunctuationIntervention::GetTitle() { return "Computer-assisted Intervention"; } bool QmitkUSNavigationStepPunctuationIntervention::GetIsRestartable() { return false; } QmitkUSNavigationStepPunctuationIntervention::FilterVector QmitkUSNavigationStepPunctuationIntervention::GetFilter() { return FilterVector(1, m_NeedleProjectionFilter.GetPointer()); } void QmitkUSNavigationStepPunctuationIntervention::OnSetCombinedModality() { - mitk::USCombinedModality::Pointer combinedModality = this->GetCombinedModality(false); + mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->GetCombinedModality(false); + m_NeedleProjectionFilter->ConnectTo(combinedModality->GetNavigationDataSource()); if ( combinedModality.IsNotNull() ) { // set calibration of the combined modality to the needle projection filter mitk::AffineTransform3D::Pointer calibration = combinedModality->GetCalibration(); if ( calibration.IsNotNull() ) { m_NeedleProjectionFilter->SetTargetPlane(calibration); } } } void QmitkUSNavigationStepPunctuationIntervention::ClearZones() { m_Ui->riskStructuresRangeWidget->ClearZones(); } void QmitkUSNavigationStepPunctuationIntervention::UpdateBodyMarkerStatus(mitk::NavigationData::Pointer bodyMarker) { if ( bodyMarker.IsNull() ) { MITK_ERROR("QmitkUSAbstractNavigationStep")("QmitkUSNavigationStepPunctuationIntervention") << "Current Navigation Data for body marker of Combined Modality must not be null."; mitkThrow() << "Current Navigation Data for body marker of Combined Modality must not be null."; } bool valid = bodyMarker->IsDataValid(); // update body marker status label if (valid) { m_Ui->bodyMarkerTrackingStatusLabel->setStyleSheet( "background-color: #8bff8b; margin-right: 1em; margin-left: 1em; border: 1px solid grey"); m_Ui->bodyMarkerTrackingStatusLabel->setText("Body marker is inside the tracking volume."); } else { m_Ui->bodyMarkerTrackingStatusLabel->setStyleSheet( "background-color: #ff7878; margin-right: 1em; margin-left: 1em; border: 1px solid grey"); m_Ui->bodyMarkerTrackingStatusLabel->setText("Body marker is not inside the tracking volume."); } m_Ui->riskStructuresRangeGroupBox->setEnabled(valid); } void QmitkUSNavigationStepPunctuationIntervention::UpdateCriticalStructures(mitk::NavigationData::Pointer needle, mitk::PointSet::Pointer path) { // update the distances for the risk structures widget m_Ui->riskStructuresRangeWidget->UpdateDistancesToNeedlePosition(needle); //iterate through all zones for (mitk::DataStorage::SetOfObjects::ConstIterator it = m_ZoneNodes->Begin(); it != m_ZoneNodes->End(); ++it) { mitk::DataNode::Pointer currentNode = it->Value(); //get center point and radius float radius = -1; mitk::Point3D center; currentNode->GetFloatProperty("zone.size", radius); center = currentNode->GetData()->GetGeometry()->GetIndexToWorldTransform()->GetTranslation(); mitk::Point3D point0 = path->GetPoint(0); mitk::Point3D point1 = path->GetPoint(1); if (CheckSphereLineIntersection(center,radius,point0,point1)) {currentNode->SetColor(mitk::IGTColor_WARNING);} else {currentNode->SetColor(m_OldColors[currentNode]);} } } bool QmitkUSNavigationStepPunctuationIntervention::CheckSphereLineIntersection(mitk::Point3D& sphereOrigin, float& sphereRadius, mitk::Point3D& lineStart, mitk::Point3D& lineEnd) { double center[3] = {sphereOrigin[0],sphereOrigin[1],sphereOrigin[2]}; m_SphereSource->SetCenter(center); m_SphereSource->SetRadius(sphereRadius); m_SphereSource->Update(); m_OBBTree->SetDataSet(m_SphereSource->GetOutput()); m_OBBTree->BuildLocator(); double lineP0[3] = {lineStart[0], lineStart[1], lineStart[2]}; double lineP1[3] = {lineEnd[0], lineEnd[1], lineEnd[2]}; m_OBBTree->IntersectWithLine(lineP0, lineP1, m_IntersectPoints, nullptr); if (m_IntersectPoints->GetNumberOfPoints() > 0) {return true;} else {return false;} } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepTumourSelection.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepTumourSelection.cpp index bd6d29d4c9..14ad0d344e 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepTumourSelection.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepTumourSelection.cpp @@ -1,428 +1,431 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkUSNavigationStepTumourSelection.h" #include "ui_QmitkUSNavigationStepTumourSelection.h" #include "usModuleRegistry.h" #include "mitkDataNode.h" #include "mitkSurface.h" #include "mitkUSCombinedModality.h" #include "../Interactors/mitkUSZonesInteractor.h" #include "mitkNodeDisplacementFilter.h" #include "QmitkUSNavigationStepCombinedModality.h" #include "../QmitkUSNavigationMarkerPlacement.h" #include "mitkIOUtil.h" #include "vtkSmartPointer.h" #include "vtkDoubleArray.h" #include "vtkPolyData.h" #include "vtkPointData.h" #include "vtkWarpScalar.h" QmitkUSNavigationStepTumourSelection::QmitkUSNavigationStepTumourSelection(QWidget* parent) : QmitkUSAbstractNavigationStep(parent), m_targetSelectionOptional(false), m_SecurityDistance(0), m_Interactor(mitk::USZonesInteractor::New()), m_NodeDisplacementFilter(mitk::NodeDisplacementFilter::New()), m_StateMachineFilename("USZoneInteractions.xml"), m_ReferenceSensorIndex(1), m_ListenerChangeNode(this, &QmitkUSNavigationStepTumourSelection::TumourNodeChanged), ui(new Ui::QmitkUSNavigationStepTumourSelection) { ui->setupUi(this); connect(ui->freezeImageButton, SIGNAL(SignalFreezed(bool)), this, SLOT(OnFreeze(bool))); connect(ui->tumourSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(OnTumourSizeChanged(int))); connect(ui->deleteTumourButton, SIGNAL(clicked()), this, SLOT(OnDeleteButtonClicked())); m_SphereColor = mitk::Color(); //default color: green m_SphereColor[0] = 0; m_SphereColor[1] = 255; m_SphereColor[2] = 0; } void QmitkUSNavigationStepTumourSelection::SetTumorColor(mitk::Color c) { m_SphereColor = c; } void QmitkUSNavigationStepTumourSelection::SetTargetSelectionOptional(bool t) { m_targetSelectionOptional = t; } QmitkUSNavigationStepTumourSelection::~QmitkUSNavigationStepTumourSelection() { delete ui; } bool QmitkUSNavigationStepTumourSelection::OnStartStep() { m_TumourNode = this->GetNamedDerivedNodeAndCreate( QmitkUSNavigationMarkerPlacement::DATANAME_TUMOUR, QmitkUSAbstractNavigationStep::DATANAME_BASENODE); m_TumourNode->SetColor(m_SphereColor[0], m_SphereColor[1], m_SphereColor[2]); // load state machine and event config for data interactor m_Interactor->LoadStateMachine(m_StateMachineFilename, us::ModuleRegistry::GetModule("MitkUS")); m_Interactor->SetEventConfig("globalConfig.xml"); this->GetDataStorage()->ChangedNodeEvent.AddListener(m_ListenerChangeNode); m_TargetSurfaceNode = this->GetNamedDerivedNodeAndCreate( QmitkUSNavigationMarkerPlacement::DATANAME_TARGETSURFACE, QmitkUSNavigationMarkerPlacement::DATANAME_TUMOUR); // do not show the surface until this is requested m_TargetSurfaceNode->SetBoolProperty("visible", false); // make sure that scalars will be renderer on the surface m_TargetSurfaceNode->SetBoolProperty("scalar visibility", true); m_TargetSurfaceNode->SetBoolProperty("color mode", true); m_TargetSurfaceNode->SetBoolProperty("Backface Culling", true); return true; } bool QmitkUSNavigationStepTumourSelection::OnStopStep() { // make sure that imaging isn't freezed anymore ui->freezeImageButton->Unfreeze(); m_NodeDisplacementFilter->ResetNodes(); mitk::DataStorage::Pointer dataStorage = this->GetDataStorage(false); if (dataStorage.IsNotNull()) { // remove target surface node from data storage, if available there if (m_TargetSurfaceNode.IsNotNull()) { dataStorage->Remove(m_TargetSurfaceNode); } dataStorage->ChangedNodeEvent.RemoveListener(m_ListenerChangeNode); dataStorage->Remove(m_TumourNode); m_TumourNode = 0; } MITK_INFO("QmitkUSAbstractNavigationStep")("QmitkUSNavigationStepTumourSelection") << "Removing tumour."; return true; } bool QmitkUSNavigationStepTumourSelection::OnRestartStep() { ui->tumourSizeExplanationLabel->setEnabled(false); ui->tumourSizeLabel->setEnabled(false); ui->tumourSizeSlider->setEnabled(false); ui->deleteTumourButton->setEnabled(false); ui->tumourSizeSlider->blockSignals(true); ui->tumourSizeSlider->setValue(0); ui->tumourSizeSlider->blockSignals(false); emit SignalNoLongerReadyForNextStep(); return QmitkUSAbstractNavigationStep::OnRestartStep(); } bool QmitkUSNavigationStepTumourSelection::OnFinishStep() { // make sure that the surface has the right extent (in case the // tumor size was changed since the initial surface creation) m_TargetSurfaceNode->SetData(this->CreateTargetSurface()); return true; } bool QmitkUSNavigationStepTumourSelection::OnActivateStep() { m_Interactor = mitk::USZonesInteractor::New(); m_Interactor->LoadStateMachine(m_StateMachineFilename, us::ModuleRegistry::GetModule("MitkUS")); m_Interactor->SetEventConfig("globalConfig.xml"); - m_NodeDisplacementFilter->SelectInput(m_ReferenceSensorIndex); + m_NodeDisplacementFilter->ConnectTo(this->GetCombinedModality()->GetNavigationDataSource()); + m_NodeDisplacementFilter->SelectInput(1);//m_ReferenceSensorIndex //target selection is optional if (m_targetSelectionOptional) { emit SignalReadyForNextStep(); } return true; } bool QmitkUSNavigationStepTumourSelection::OnDeactivateStep() { m_Interactor->SetDataNode(0); bool value; if (m_TumourNode.IsNotNull() && !(m_TumourNode->GetBoolProperty("zone.created", value) && value)) { m_TumourNode->SetData(0); } // make sure that imaging isn't freezed anymore ui->freezeImageButton->Unfreeze(); return true; } void QmitkUSNavigationStepTumourSelection::OnUpdate() { if (m_NavigationDataSource.IsNull()) { return; } m_NavigationDataSource->Update(); + m_NodeDisplacementFilter->Update(); bool valid = m_NavigationDataSource->GetOutput(m_ReferenceSensorIndex)->IsDataValid(); if (valid) { ui->bodyMarkerTrackingStatusLabel->setStyleSheet( "background-color: #8bff8b; margin-right: 1em; margin-left: 1em; border: 1px solid grey"); ui->bodyMarkerTrackingStatusLabel->setText("Body marker is inside the tracking volume."); } else { ui->bodyMarkerTrackingStatusLabel->setStyleSheet( "background-color: #ff7878; margin-right: 1em; margin-left: 1em; border: 1px solid grey"); ui->bodyMarkerTrackingStatusLabel->setText("Body marker is not inside the tracking volume."); } ui->freezeImageButton->setEnabled(valid); bool created; if (m_TumourNode.IsNull() || !m_TumourNode->GetBoolProperty("zone.created", created) || !created) { ui->tumourSearchExplanationLabel->setEnabled(valid); } } void QmitkUSNavigationStepTumourSelection::OnSettingsChanged(const itk::SmartPointer settingsNode) { if (settingsNode.IsNull()) { return; } float securityDistance; if (settingsNode->GetFloatProperty("settings.security-distance", securityDistance)) { m_SecurityDistance = securityDistance; } std::string stateMachineFilename; if (settingsNode->GetStringProperty("settings.interaction-concept", stateMachineFilename) && stateMachineFilename != m_StateMachineFilename) { m_StateMachineFilename = stateMachineFilename; m_Interactor->LoadStateMachine(stateMachineFilename, us::ModuleRegistry::GetModule("MitkUS")); } std::string referenceSensorName; if (settingsNode->GetStringProperty("settings.reference-name-selected", referenceSensorName)) { m_ReferenceSensorName = referenceSensorName; } this->UpdateReferenceSensorName(); } QString QmitkUSNavigationStepTumourSelection::GetTitle() { return "Localisation of Tumour Position"; } QmitkUSAbstractNavigationStep::FilterVector QmitkUSNavigationStepTumourSelection::GetFilter() { return FilterVector(1, m_NodeDisplacementFilter.GetPointer()); } void QmitkUSNavigationStepTumourSelection::OnFreeze(bool freezed) { - if (freezed) this->GetCombinedModality()->SetIsFreezed(true); + if (freezed) this->GetCombinedModality()->GetUltrasoundDevice()->SetIsFreezed(true); ui->tumourSelectionExplanation1Label->setEnabled(freezed); ui->tumourSelectionExplanation2Label->setEnabled(freezed); if (freezed) { if (!m_TumourNode->GetData()) { // load state machine and event config for data interactor m_Interactor->LoadStateMachine(m_StateMachineFilename, us::ModuleRegistry::GetModule("MitkUS")); m_Interactor->SetEventConfig("globalConfig.xml"); m_Interactor->SetDataNode(m_TumourNode); // feed reference pose to node displacement filter m_NodeDisplacementFilter->SetInitialReferencePose(this->GetCombinedModality()->GetNavigationDataSource()->GetOutput(m_ReferenceSensorIndex)->Clone()); } } else { bool value; if (m_TumourNode->GetBoolProperty("zone.created", value) && value) { ui->freezeImageButton->setEnabled(false); ui->tumourSearchExplanationLabel->setEnabled(false); } } - if (!freezed) this->GetCombinedModality()->SetIsFreezed(false); + if (!freezed) this->GetCombinedModality()->GetUltrasoundDevice()->SetIsFreezed(false); } void QmitkUSNavigationStepTumourSelection::OnSetCombinedModality() { - mitk::USCombinedModality::Pointer combinedModality = this->GetCombinedModality(false); + mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->GetCombinedModality(false); if (combinedModality.IsNotNull()) { m_NavigationDataSource = combinedModality->GetNavigationDataSource(); } else { m_NavigationDataSource = 0; } ui->freezeImageButton->SetCombinedModality(combinedModality, m_ReferenceSensorIndex); this->UpdateReferenceSensorName(); } void QmitkUSNavigationStepTumourSelection::OnTumourSizeChanged(int size) { m_TumourNode->SetFloatProperty("zone.size", static_cast(size)); mitk::USZonesInteractor::UpdateSurface(m_TumourNode); MITK_INFO("QmitkUSAbstractNavigationStep")("QmitkUSNavigationStepTumourSelection") << "Changing tumour radius to " << size << "."; } void QmitkUSNavigationStepTumourSelection::OnDeleteButtonClicked() { this->OnRestartStep(); } void QmitkUSNavigationStepTumourSelection::TumourNodeChanged(const mitk::DataNode* dataNode) { // only changes of tumour node are of interest if (dataNode != m_TumourNode) { return; } float size; dataNode->GetFloatProperty("zone.size", size); ui->tumourSizeSlider->setValue(static_cast(size)); bool created; if (dataNode->GetBoolProperty("zone.created", created) && created) { if (ui->freezeImageButton->isChecked()) { m_NodeDisplacementFilter->AddNode(const_cast(dataNode)); m_TargetSurfaceNode->SetData(this->CreateTargetSurface()); m_NodeDisplacementFilter->AddNode(m_TargetSurfaceNode); MITK_INFO("QmitkUSAbstractNavigationStep")("QmitkUSNavigationStepTumourSelection") << "Tumour created with center " << dataNode->GetData()->GetGeometry()->GetOrigin() << " and radius " << size << "."; mitk::DataNode::Pointer tumourResultNode = mitk::DataNode::New(); tumourResultNode->SetName("TumourResult"); tumourResultNode->SetProperty("USNavigation::TumourCenter", mitk::Point3dProperty::New(dataNode->GetData()->GetGeometry()->GetOrigin())); tumourResultNode->SetProperty("USNavigation::TumourRadius", mitk::DoubleProperty::New(size)); emit SignalIntermediateResult(tumourResultNode); ui->freezeImageButton->Unfreeze(); } ui->tumourSearchExplanationLabel->setEnabled(false); ui->tumourSizeExplanationLabel->setEnabled(true); ui->tumourSizeLabel->setEnabled(true); ui->tumourSizeSlider->setEnabled(true); ui->deleteTumourButton->setEnabled(true); emit SignalReadyForNextStep(); } } mitk::Surface::Pointer QmitkUSNavigationStepTumourSelection::CreateTargetSurface() { mitk::Surface::Pointer tumourSurface = dynamic_cast(m_TumourNode->GetData()); if (tumourSurface.IsNull()) { MITK_WARN << "No target selected, cannot create surface!"; return mitk::Surface::New(); //return a empty surface in this case... } // make a deep copy of the tumour surface polydata vtkSmartPointer tumourSurfaceVtk = vtkSmartPointer::New(); tumourSurfaceVtk->DeepCopy(tumourSurface->GetVtkPolyData()); // create scalars for moving every point the same size onto its normal vector vtkSmartPointer scalars = vtkSmartPointer::New(); int numberOfPoints = tumourSurfaceVtk->GetNumberOfPoints(); scalars->SetNumberOfTuples(numberOfPoints); // set scalars for warp filter for (vtkIdType i = 0; i < numberOfPoints; ++i) { scalars->SetTuple1(i, m_SecurityDistance * 10); } tumourSurfaceVtk->GetPointData()->SetScalars(scalars); vtkSmartPointer warpScalar = vtkSmartPointer::New(); warpScalar->SetInputData(tumourSurfaceVtk); warpScalar->SetScaleFactor(1); // use the scalars themselves warpScalar->Update(); vtkSmartPointer targetSurfaceVtk = warpScalar->GetPolyDataOutput(); // set the moved points to the deep copied tumour surface; this is // necessary as setting the targetSurfaceVtk as polydata for the // targetSurface would result in flat shading for the surface (seems // to be a bug in MITK or VTK) tumourSurfaceVtk->SetPoints(targetSurfaceVtk->GetPoints()); mitk::Surface::Pointer targetSurface = mitk::Surface::New(); targetSurface->SetVtkPolyData(tumourSurfaceVtk); targetSurface->GetGeometry()->SetOrigin(tumourSurface->GetGeometry()->GetOrigin()); return targetSurface; } itk::SmartPointer QmitkUSNavigationStepTumourSelection::GetTumourNodeDisplacementFilter() { return m_NodeDisplacementFilter; } void QmitkUSNavigationStepTumourSelection::UpdateReferenceSensorName() { if (m_NavigationDataSource.IsNull()) { return; } if (!m_ReferenceSensorName.empty()) { try { m_ReferenceSensorIndex = m_NavigationDataSource->GetOutputIndex(m_ReferenceSensorName); } catch (const std::exception &e) { MITK_WARN("QmitkUSAbstractNavigationStep")("QmitkUSNavigationStepTumourSelection") << "Cannot get index for reference sensor name: " << e.what(); } } if (this->GetNavigationStepState() >= QmitkUSAbstractNavigationStep::State_Active) { + MITK_INFO << "############### " << m_NodeDisplacementFilter->GetNumberOfIndexedInputs(); m_NodeDisplacementFilter->SelectInput(m_ReferenceSensorIndex); } ui->freezeImageButton->SetCombinedModality(this->GetCombinedModality(false), m_ReferenceSensorIndex); } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepZoneMarking.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepZoneMarking.cpp index ffe7a26b38..06fa4cb5d3 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepZoneMarking.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepZoneMarking.cpp @@ -1,269 +1,272 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkUSNavigationStepZoneMarking.h" #include "ui_QmitkUSNavigationStepZoneMarking.h" #include "mitkNodeDisplacementFilter.h" #include "../QmitkUSNavigationMarkerPlacement.h" QmitkUSNavigationStepZoneMarking::QmitkUSNavigationStepZoneMarking(QWidget *parent) : QmitkUSAbstractNavigationStep(parent), m_ZoneDisplacementFilter(mitk::NodeDisplacementFilter::New()), m_ReferenceSensorIndex(1), m_CurrentlyAddingZone(false), ui(new Ui::QmitkUSNavigationStepZoneMarking) { ui->setupUi(this); connect( ui->freezeButton, SIGNAL(SignalFreezed(bool)), this, SLOT(OnFreeze(bool)) ); connect( ui->zonesWidget, SIGNAL(ZoneAdded()), this, SLOT(OnZoneAdded()) ); connect( ui->zonesWidget, SIGNAL(ZoneRemoved()), this, SLOT(OnZoneRemoved()) ); connect(ui->showStructureList, SIGNAL(stateChanged(int)), this, SLOT(OnShowListClicked(int))); ui->zonesLabel->setVisible(false); ui->zonesWidget->setVisible(false); } void QmitkUSNavigationStepZoneMarking::OnShowListClicked(int state) { ui->zonesLabel->setVisible(state); ui->zonesWidget->setVisible(state); } QmitkUSNavigationStepZoneMarking::~QmitkUSNavigationStepZoneMarking() { delete ui; } bool QmitkUSNavigationStepZoneMarking::OnStartStep() { this->GetNamedDerivedNodeAndCreate(QmitkUSNavigationMarkerPlacement::DATANAME_ZONES, QmitkUSAbstractNavigationStep::DATANAME_BASENODE); ui->zonesWidget->SetDataStorage(this->GetDataStorage(), QmitkUSNavigationMarkerPlacement::DATANAME_ZONES); return true; } bool QmitkUSNavigationStepZoneMarking::OnStopStep() { m_ZoneDisplacementFilter->ResetNodes(); ui->zonesWidget->OnResetZones(); m_ZoneNodes.clear(); // remove zone nodes from the data storage mitk::DataStorage::Pointer dataStorage = this->GetDataStorage(false); if ( dataStorage.IsNotNull() ) { mitk::DataNode::Pointer baseNode = dataStorage->GetNamedNode(QmitkUSAbstractNavigationStep::DATANAME_BASENODE); if ( baseNode.IsNotNull() ) { dataStorage->Remove(dataStorage->GetNamedDerivedNode(QmitkUSNavigationMarkerPlacement::DATANAME_ZONES, baseNode)); } } return true; } bool QmitkUSNavigationStepZoneMarking::OnFinishStep() { return true; } bool QmitkUSNavigationStepZoneMarking::OnActivateStep() { + m_ZoneDisplacementFilter->ConnectTo(this->GetCombinedModality()->GetNavigationDataSource()); m_ZoneDisplacementFilter->SelectInput(m_ReferenceSensorIndex); emit SignalReadyForNextStep(); return true; } bool QmitkUSNavigationStepZoneMarking::OnDeactivateStep() { ui->freezeButton->Unfreeze(); return true; } void QmitkUSNavigationStepZoneMarking::OnUpdate() { if (m_NavigationDataSource.IsNull()) { return; } m_NavigationDataSource->Update(); + m_ZoneDisplacementFilter->Update(); bool valid = m_NavigationDataSource->GetOutput(m_ReferenceSensorIndex)->IsDataValid(); if (valid) { ui->bodyMarkerTrackingStatusLabel->setStyleSheet( "background-color: #8bff8b; margin-right: 1em; margin-left: 1em; border: 1px solid grey"); ui->bodyMarkerTrackingStatusLabel->setText("Body marker is inside the tracking volume."); } else { ui->bodyMarkerTrackingStatusLabel->setStyleSheet( "background-color: #ff7878; margin-right: 1em; margin-left: 1em; border: 1px solid grey"); ui->bodyMarkerTrackingStatusLabel->setText("Body marker is not inside the tracking volume."); } ui->freezeButton->setEnabled(valid); } void QmitkUSNavigationStepZoneMarking::OnSettingsChanged(const itk::SmartPointer settingsNode) { if ( settingsNode.IsNull() ) { return; } std::string stateMachineFilename; if ( settingsNode->GetStringProperty("settings.interaction-concept", stateMachineFilename) && stateMachineFilename != m_StateMachineFilename ) { m_StateMachineFilename = stateMachineFilename; ui->zonesWidget->SetStateMachineFilename(stateMachineFilename); } std::string referenceSensorName; if ( settingsNode->GetStringProperty("settings.reference-name-selected", referenceSensorName) ) { m_ReferenceSensorName = referenceSensorName; } this->UpdateReferenceSensorName(); } QString QmitkUSNavigationStepZoneMarking::GetTitle() { return "Critical Structures"; } QmitkUSAbstractNavigationStep::FilterVector QmitkUSNavigationStepZoneMarking::GetFilter() { return FilterVector(1, m_ZoneDisplacementFilter.GetPointer()); } void QmitkUSNavigationStepZoneMarking::OnFreeze(bool freezed) { - if (freezed) this->GetCombinedModality()->SetIsFreezed(true); + if (freezed) this->GetCombinedModality()->GetUltrasoundDevice()->SetIsFreezed(true); ui->zoneAddingExplanationLabel->setEnabled(freezed); if ( freezed ) { m_CurrentlyAddingZone = true; ui->zonesWidget->OnStartAddingZone(); // feed reference pose to node displacement filter m_ZoneDisplacementFilter->SetInitialReferencePose(this->GetCombinedModality()->GetNavigationDataSource()->GetOutput(m_ReferenceSensorIndex)->Clone()); } else if ( m_CurrentlyAddingZone ) { m_CurrentlyAddingZone = false; ui->zonesWidget->OnAbortAddingZone(); } - if (!freezed) this->GetCombinedModality()->SetIsFreezed(false); + if (!freezed) this->GetCombinedModality()->GetUltrasoundDevice()->SetIsFreezed(false); } void QmitkUSNavigationStepZoneMarking::OnZoneAdded() { m_CurrentlyAddingZone = false; ui->freezeButton->Unfreeze(); ui->zoneAddingExplanationLabel->setEnabled(ui->freezeButton->isChecked()); mitk::DataStorage::SetOfObjects::ConstPointer zoneNodesSet = ui->zonesWidget->GetZoneNodes(); for (mitk::DataStorage::SetOfObjects::ConstIterator it = zoneNodesSet->Begin(); it != zoneNodesSet->End(); ++it) { // add all zones to zone filter which aren't added until now if ( std::find(m_ZoneNodes.begin(), m_ZoneNodes.end(), it->Value()) == m_ZoneNodes.end() ) { // logging center point and radius float radius = -1; it->Value()->GetFloatProperty("zone.size", radius); MITK_INFO("QmitkUSNavigationStepZoneMarking")("QmitkUSAbstractNavigationStep") << "Risk zone (" << it->Value()->GetName() << ") added with center " << it->Value()->GetData()->GetGeometry()->GetOrigin() << " and radius " << radius << "."; m_ZoneNodes.push_back(it->Value()); m_ZoneDisplacementFilter->AddNode(it->Value()); } } } void QmitkUSNavigationStepZoneMarking::OnZoneRemoved() { mitk::DataStorage::SetOfObjects::ConstPointer zoneNodesSet = ui->zonesWidget->GetZoneNodes(); for ( int n = m_ZoneNodes.size() - 1; n >= 0; --n ) { bool found = false; // test if the node can be found in the set of zone nodes for (mitk::DataStorage::SetOfObjects::ConstIterator itSet = zoneNodesSet->Begin(); itSet != zoneNodesSet->End(); ++itSet) { if ( m_ZoneNodes.at(n) == itSet->Value() ) { found = true; break; } } if ( ! found ) { MITK_INFO("QmitkUSNavigationStepZoneMarking")("QmitkUSAbstractNavigationStep") << "Risk zone (" << m_ZoneNodes.at(n)->GetName() << ") removed."; m_ZoneNodes.erase(m_ZoneNodes.begin()+n); m_ZoneDisplacementFilter->RemoveNode(n); } } } void QmitkUSNavigationStepZoneMarking::OnSetCombinedModality() { - mitk::USCombinedModality::Pointer combinedModality = this->GetCombinedModality(false); + mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->GetCombinedModality(false); if (combinedModality.IsNotNull()) { m_NavigationDataSource = combinedModality->GetNavigationDataSource(); } ui->freezeButton->SetCombinedModality(combinedModality, m_ReferenceSensorIndex); this->UpdateReferenceSensorName(); } void QmitkUSNavigationStepZoneMarking::UpdateReferenceSensorName() { if ( m_NavigationDataSource.IsNull() ) { return; } if ( ! m_ReferenceSensorName.empty() ) { try { - m_ReferenceSensorIndex = m_NavigationDataSource->GetOutputIndex(m_ReferenceSensorName); + //m_ReferenceSensorIndex = m_NavigationDataSource->GetOutputIndex(m_ReferenceSensorName); + m_ReferenceSensorIndex = 1; } catch ( const std::exception &e ) { MITK_WARN("QmitkUSAbstractNavigationStep")("QmitkUSNavigationStepZoneMarking") << "Cannot get index for reference sensor name: " << e.what(); } } if ( this->GetNavigationStepState() >= QmitkUSAbstractNavigationStep::State_Active ) { m_ZoneDisplacementFilter->SelectInput(m_ReferenceSensorIndex); } ui->freezeButton->SetCombinedModality(this->GetCombinedModality(false), m_ReferenceSensorIndex); } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationCalibrationsDataModel.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationCalibrationsDataModel.cpp index 0258f3b058..988a5a9170 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationCalibrationsDataModel.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationCalibrationsDataModel.cpp @@ -1,250 +1,250 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkUSNavigationCalibrationsDataModel.h" #include #include #include #include #include #include QmitkUSNavigationCalibrationsDataModel::QmitkUSNavigationCalibrationsDataModel(QObject *parent) : QAbstractTableModel(parent), m_ListenerDeviceChanged(this, &QmitkUSNavigationCalibrationsDataModel::OnDeviceChanged) { } QmitkUSNavigationCalibrationsDataModel::~QmitkUSNavigationCalibrationsDataModel() { if ( m_CombinedModality.IsNotNull() ) { m_CombinedModality->GetUltrasoundDevice()->RemovePropertyChangedListener(m_ListenerDeviceChanged); } } - void QmitkUSNavigationCalibrationsDataModel::SetCombinedModality(mitk::USCombinedModality::Pointer combinedModality) + void QmitkUSNavigationCalibrationsDataModel::SetCombinedModality(mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality) { if ( m_CombinedModality.IsNotNull() && m_CombinedModality->GetUltrasoundDevice().IsNotNull() ) { m_CombinedModality->GetUltrasoundDevice()->RemovePropertyChangedListener(m_ListenerDeviceChanged); } m_CombinedModality = combinedModality; if ( m_CombinedModality.IsNotNull() ) { m_ControlInterfaceBMode = m_CombinedModality->GetControlInterfaceBMode(); // make sure that the combined modality is active as this may be // necessary to get the available depths - if ( m_CombinedModality->GetDeviceState() < mitk::USDevice::State_Connected ) { m_CombinedModality->Connect(); } - if ( m_CombinedModality->GetDeviceState() == mitk::USDevice::State_Connected ) { m_CombinedModality->Activate(); } + if ( m_CombinedModality->GetUltrasoundDevice()->GetDeviceState() < mitk::USDevice::State_Connected ) { m_CombinedModality->GetUltrasoundDevice()->Connect(); } + if ( m_CombinedModality->GetUltrasoundDevice()->GetDeviceState() == mitk::USDevice::State_Connected ) { m_CombinedModality->GetUltrasoundDevice()->Activate(); } if ( m_CombinedModality->GetUltrasoundDevice().IsNotNull() ) { m_CombinedModality->GetUltrasoundDevice()->AddPropertyChangedListener(m_ListenerDeviceChanged); } } // as the combined modality was changed, an old table model // would not be valid anymore this->beginResetModel(); this->endResetModel(); } void QmitkUSNavigationCalibrationsDataModel::OnDeviceChanged(const std::string&, const std::string&) { this->beginResetModel(); this->endResetModel(); } /** \brief Return number of rows of the model. */ int QmitkUSNavigationCalibrationsDataModel::rowCount ( const QModelIndex & ) const { if ( m_ControlInterfaceBMode.IsNull() ) { return 1; // only one default depth can be assumed } else { return m_ControlInterfaceBMode->GetScanningDepthValues().size(); } } /** \brief Return number of columns (3) of the model. */ int QmitkUSNavigationCalibrationsDataModel::columnCount ( const QModelIndex & ) const { return 3; } /** \brief Return names for the columns, numbers for the rows and invalid for DisplayRole. */ QVariant QmitkUSNavigationCalibrationsDataModel::headerData ( int section, Qt::Orientation orientation, int role ) const { if ( role != Qt::DisplayRole ) { return QVariant(QVariant::Invalid); } if ( orientation == Qt::Horizontal ) { switch ( section ) { case 0: return QVariant("Depth"); case 1: return QVariant("Calibrated"); case 2: return QVariant(""); } } return QVariant(QVariant::Invalid); } /** \brief Return selectable and enabled for column 1 (size); selectable, enabled and editable for every other column. */ Qt::ItemFlags QmitkUSNavigationCalibrationsDataModel::flags ( const QModelIndex & ) const { return Qt::ItemIsSelectable | Qt::ItemIsEnabled; } /** \brief Return model data of the selected cell. */ QVariant QmitkUSNavigationCalibrationsDataModel::data ( const QModelIndex & index, int role ) const { if ( m_CombinedModality.IsNull() ) { return QVariant(QVariant::Invalid); } std::vector scanningDepthValues = m_ControlInterfaceBMode.IsNull() ? std::vector(1,0) : m_ControlInterfaceBMode->GetScanningDepthValues(); // make sure that row and column index fit data borders if (index.row() >= this->rowCount() || index.column() >= this->columnCount()) { return QVariant(QVariant::Invalid); } double currentDepth = 0; if ( m_ControlInterfaceBMode.IsNotNull() ) { currentDepth = m_ControlInterfaceBMode->GetScanningDepth(); } bool isCalibratedForCurrentDepth = m_CombinedModality->GetCalibration(QString::number(scanningDepthValues.at(index.row())).toStdString()).IsNotNull(); switch (role) { case Qt::BackgroundColorRole: { if ( isCalibratedForCurrentDepth ) { return QVariant(QBrush(QColor(125, 255, 125))); } else { return QVariant(QBrush(QColor(255, 125, 125))); } break; } case Qt::FontRole: { if ( scanningDepthValues.at(index.row()) == currentDepth ) { QFont qFont; qFont.setBold(true); return qFont; } else { return QVariant::Invalid; } } case Qt::DecorationRole: { if ( index.column() == 2 ) { if ( isCalibratedForCurrentDepth ) { return QIcon(":/USNavigation/process-stop.png"); } } else { return QVariant::Invalid; } } case Qt::EditRole: case Qt::DisplayRole: { switch ( index.column() ) { case 0: { return QVariant::fromValue(scanningDepthValues.at(index.row())); } case 1: { if ( m_ControlInterfaceBMode.IsNull() ) { // use the current zoom level (which is assumed to be the only one), // when no b mode controls are available return QVariant(m_CombinedModality->GetCalibration().IsNotNull()); } else { return QVariant(isCalibratedForCurrentDepth); } } case 2: { return QVariant(""); } } break; } case Qt::ToolTipRole: { if ( index.column() == 2 && isCalibratedForCurrentDepth ) { return QVariant(QString("Remove calibration for depth ") + QString::number(scanningDepthValues.at(index.row())) + " on mouse click."); } break; } } return QVariant(QVariant::Invalid); } /** \brief Set model data for the selected cell. */ bool QmitkUSNavigationCalibrationsDataModel::setData ( const QModelIndex & index, const QVariant & value, int ) { if ( m_CombinedModality.IsNull() || index.column() != 2 || value != false ) return false; if ( m_ControlInterfaceBMode.IsNull() ) { m_CombinedModality->RemoveCalibration(); } else { m_CombinedModality->RemoveCalibration(QString::number(m_ControlInterfaceBMode->GetScanningDepthValues().at(index.row())).toStdString()); } emit dataChanged(this->index(index.row(), 0), this->index(index.row(), 1)); return true; } /** \brief Remove given rows from the model. * \param removeFromDataStorage zone nodes are removed from the data storage too, if this is set to true */ bool QmitkUSNavigationCalibrationsDataModel::removeRows ( int, int, const QModelIndex&, bool ) { return false; } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationCalibrationsDataModel.h b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationCalibrationsDataModel.h index 358b15fb10..db16f09fcd 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationCalibrationsDataModel.h +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationCalibrationsDataModel.h @@ -1,74 +1,74 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKUSNAVIGATIONCALIBRATIONSDATAMODEL_H #define QMITKUSNAVIGATIONCALIBRATIONSDATAMODEL_H #include #include #include namespace mitk { - class USCombinedModality; + class AbstractUltrasoundTrackerDevice; class USControlInterfaceBMode; class USControlInterfaceProbes; } class QmitkUSNavigationCalibrationsDataModel : public QAbstractTableModel { Q_OBJECT public: explicit QmitkUSNavigationCalibrationsDataModel(QObject *parent = 0); virtual ~QmitkUSNavigationCalibrationsDataModel(); - void SetCombinedModality(itk::SmartPointer combinedModality); + void SetCombinedModality(itk::SmartPointer combinedModality); void OnDeviceChanged(const std::string&, const std::string&); /** \brief Return number of rows of the model. */ virtual int rowCount ( const QModelIndex & parent = QModelIndex() ) const; /** \brief Return number of columns (3) of the model. */ virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const; /** \brief Return names for the columns, numbers for the rows and invalid for DisplayRole. */ virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; /** \brief Return selectable and enabled for column 1 (size); selectable, enabled and editable for every other column. */ virtual Qt::ItemFlags flags ( const QModelIndex & index ) const; /** \brief Return model data of the selected cell. */ virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const; /** \brief Set model data for the selected cell. */ virtual bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole ); using QAbstractTableModel::removeRows; /** \brief Remove given rows from the model. * \param removeFromDataStorage zone nodes are removed from the data storage too, if this is set to true */ virtual bool removeRows ( int row, int count, const QModelIndex& parent, bool removeFromDataStorage ); private: - itk::SmartPointer m_CombinedModality; + itk::SmartPointer m_CombinedModality; itk::SmartPointer m_ControlInterfaceBMode; mitk::MessageDelegate2 m_ListenerDeviceChanged; }; #endif // QMITKUSNAVIGATIONCALIBRATIONSDATAMODEL_H diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationMarkerPlacement.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationMarkerPlacement.cpp index 843a7144dd..e8d39b965d 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationMarkerPlacement.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationMarkerPlacement.cpp @@ -1,875 +1,706 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkUSNavigationMarkerPlacement.h" #include "ui_QmitkUSNavigationMarkerPlacement.h" #include "NavigationStepWidgets/QmitkUSNavigationStepCombinedModality.h" #include "NavigationStepWidgets/QmitkUSNavigationStepMarkerIntervention.h" #include "NavigationStepWidgets/QmitkUSNavigationStepPlacementPlanning.h" #include "NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.h" #include "NavigationStepWidgets/QmitkUSNavigationStepTumourSelection.h" #include "NavigationStepWidgets/QmitkUSNavigationStepZoneMarking.h" #include "SettingsWidgets/QmitkUSNavigationCombinedSettingsWidget.h" #include "mitkIRenderingManager.h" #include "mitkNodeDisplacementFilter.h" -#include "mitkUSCombinedModality.h" +#include "mitkAbstractUltrasoundTrackerDevice.h" #include #include "IO/mitkUSNavigationExperimentLogging.h" #include "IO/mitkUSNavigationStepTimer.h" #include #include #include #include #include #include #include "QmitkRenderWindow.h" #include "QmitkStdMultiWidget.h" #include "QmitkStdMultiWidgetEditor.h" #include "mitkLayoutAnnotationRenderer.h" #include "mitkCameraController.h" // scene serialization #include #include #include #include #include const std::string QmitkUSNavigationMarkerPlacement::VIEW_ID = "org.mitk.views.usmarkerplacement"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TUMOUR = "Tumour"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TARGETSURFACE = "Target Surface"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_ZONES = "Zones"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS = "Targets"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS_PATHS = "Target Paths"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_REACHED_TARGETS = "Reached Targets"; QmitkUSNavigationMarkerPlacement::QmitkUSNavigationMarkerPlacement() : m_Parent(nullptr), - m_NavigationSteps(), m_UpdateTimer(new QTimer(this)), m_ImageAndNavigationDataLoggingTimer(new QTimer(this)), m_StdMultiWidget(nullptr), m_CombinedModality(nullptr), m_ReinitAlreadyDone(false), m_IsExperimentRunning(false), m_CurrentApplicationName(), m_NavigationStepTimer(mitk::USNavigationStepTimer::New()), m_ExperimentLogging(mitk::USNavigationExperimentLogging::New()), m_IconRunning(QPixmap(":/USNavigation/record.png")), m_IconNotRunning(QPixmap(":/USNavigation/record-gray.png")), m_ResultsDirectory(), m_ExperimentName(), m_ExperimentResultsSubDirectory(), m_NavigationStepNames(), m_LoggingBackend(), m_USImageLoggingFilter(mitk::USImageLoggingFilter::New()), m_NavigationDataRecorder(mitk::NavigationDataRecorder::New()), m_TargetNodeDisplacementFilter(nullptr), m_AblationZonesDisplacementFilter(mitk::NodeDisplacementFilter::New()), m_AblationZonesVector(), m_NeedleIndex(0), m_MarkerIndex(1), m_SceneNumber(1), m_WarnOverlay(mitk::TextAnnotation2D::New()), m_NavigationDataSource(nullptr), m_CurrentStorage(nullptr), - m_ListenerDeviceChanged(this, &QmitkUSNavigationMarkerPlacement::OnCombinedModalityPropertyChanged), ui(new Ui::QmitkUSNavigationMarkerPlacement ) { connect(m_UpdateTimer, SIGNAL(timeout()), this, SLOT(OnTimeout())); connect( m_ImageAndNavigationDataLoggingTimer, SIGNAL(timeout()), this, SLOT(OnImageAndNavigationDataLoggingTimeout())); // scale running (and not running) icon the specific height m_IconRunning = m_IconRunning.scaledToHeight(20, Qt::SmoothTransformation); m_IconNotRunning = m_IconNotRunning.scaledToHeight(20, Qt::SmoothTransformation); // set prefix for experiment logging (only keys with this prefix are taken // into consideration m_ExperimentLogging->SetKeyPrefix("USNavigation::"); m_UpdateTimer->start(33); // every 33 Milliseconds = 30 Frames/Second } QmitkUSNavigationMarkerPlacement::~QmitkUSNavigationMarkerPlacement() { - // remove listener for ultrasound device changes - if (m_CombinedModality.IsNotNull() && m_CombinedModality->GetUltrasoundDevice().IsNotNull()) - { - m_CombinedModality->GetUltrasoundDevice()->RemovePropertyChangedListener(m_ListenerDeviceChanged); - } - - // remove listener for ultrasound device changes - if (m_CombinedModality.IsNotNull() && m_CombinedModality->GetUltrasoundDevice().IsNotNull()) - { - m_CombinedModality->GetUltrasoundDevice()->RemovePropertyChangedListener(m_ListenerDeviceChanged); - } - delete ui; } void QmitkUSNavigationMarkerPlacement::OnChangeAblationZone(int id, int newSize) { if ((static_cast(m_AblationZonesVector.size()) < id) || (id < 0)) { return; } MITK_INFO << "Ablation Zone " << id << " changed, new size: " << newSize; // create a vtk sphere with given radius vtkSphereSource *vtkData = vtkSphereSource::New(); vtkData->SetRadius(newSize / 2); vtkData->SetCenter(0, 0, 0); vtkData->SetPhiResolution(20); vtkData->SetThetaResolution(20); vtkData->Update(); mitk::Surface::Pointer zoneSurface = dynamic_cast(m_AblationZonesVector.at(id)->GetData()); zoneSurface->SetVtkPolyData(vtkData->GetOutput()); vtkData->Delete(); } void QmitkUSNavigationMarkerPlacement::OnAddAblationZone(int size) { m_AblationZonesDisplacementFilter->SetInitialReferencePose( m_CombinedModality->GetNavigationDataSource()->GetOutput(m_MarkerIndex)); mitk::DataNode::Pointer NewAblationZone = mitk::DataNode::New(); mitk::Point3D origin = m_CombinedModality->GetNavigationDataSource()->GetOutput(m_NeedleIndex)->GetPosition(); MITK_INFO("USNavigationLogging") << "Ablation Zone Added, initial size: " << size << ", origin: " << origin; mitk::Surface::Pointer zone = mitk::Surface::New(); // create a vtk sphere with given radius vtkSphereSource *vtkData = vtkSphereSource::New(); vtkData->SetRadius(size / 2); vtkData->SetCenter(0, 0, 0); vtkData->SetPhiResolution(20); vtkData->SetThetaResolution(20); vtkData->Update(); zone->SetVtkPolyData(vtkData->GetOutput()); vtkData->Delete(); // set vtk sphere and origin to data node (origin must be set // again, because of the new sphere set as data) NewAblationZone->SetData(zone); NewAblationZone->GetData()->GetGeometry()->SetOrigin(origin); mitk::Color SphereColor = mitk::Color(); // default color SphereColor[0] = 102; SphereColor[1] = 0; SphereColor[2] = 204; NewAblationZone->SetColor(SphereColor); NewAblationZone->SetOpacity(0.3); // set name of zone std::stringstream name; name << "Ablation Zone" << m_AblationZonesVector.size(); NewAblationZone->SetName(name.str()); // add zone to filter m_AblationZonesDisplacementFilter->AddNode(NewAblationZone); m_AblationZonesVector.push_back(NewAblationZone); this->GetDataStorage()->Add(NewAblationZone); } void QmitkUSNavigationMarkerPlacement::CreateQtPartControl(QWidget *parent) { m_Parent = parent; ui->setupUi(parent); - - connect(ui->navigationProcessWidget, - SIGNAL(SignalCombinedModalityChanged(itk::SmartPointer)), - this, - SLOT(OnCombinedModalityChanged(itk::SmartPointer))); - - connect(ui->navigationProcessWidget, - SIGNAL(SignalSettingsChanged(itk::SmartPointer)), - this, - SLOT(OnSettingsChanged(itk::SmartPointer))); - - connect(ui->navigationProcessWidget, - SIGNAL(SignalActiveNavigationStepChanged(int)), - this, - SLOT(OnActiveNavigationStepChanged(int))); - - connect(ui->navigationProcessWidget, - SIGNAL(SignalActiveNavigationStepChangeRequested(int)), - this, - SLOT(OnNextNavigationStepInitialization(int))); - + connect(ui->startExperimentButton, SIGNAL(clicked()), this, SLOT(OnStartExperiment())); connect(ui->finishExperimentButton, SIGNAL(clicked()), this, SLOT(OnFinishExperiment())); connect(ui->m_enableNavigationLayout, SIGNAL(clicked()), this, SLOT(OnChangeLayoutClicked())); connect(ui->m_RenderWindowSelection, SIGNAL(valueChanged(int)), this, SLOT(OnRenderWindowSelection())); connect(ui->m_RefreshView, SIGNAL(clicked()), this, SLOT(OnRefreshView())); - connect(ui->navigationProcessWidget, - SIGNAL(SignalIntermediateResult(const itk::SmartPointer)), - this, - SLOT(OnIntermediateResultProduced(const itk::SmartPointer))); - ui->navigationProcessWidget->SetDataStorage(this->GetDataStorage()); + connect(ui->m_initializeTargetMarking, SIGNAL(clicked()), this, SLOT(OnInitializeTargetMarking())); + connect(ui->m_initializeCritStructureMarking, SIGNAL(clicked()), this, SLOT(OnInitializeCriticalStructureMarking())); + connect(ui->m_initializeNavigation, SIGNAL(clicked()), this, SLOT(OnInitializeNavigation())); + // indicate that no experiment is running at start ui->runningLabel->setPixmap(m_IconNotRunning); + connect(ui->m_settingsWidget, SIGNAL(SettingsChanged(itk::SmartPointer)), this, SLOT(OnSettingsChanged(itk::SmartPointer))); + ui->navigationProcessWidget->SetSettingsWidget(new QmitkUSNavigationCombinedSettingsWidget(m_Parent)); } +void QmitkUSNavigationMarkerPlacement::OnInitializeTargetMarking() +{ + m_SettingsNode = mitk::DataNode::New(); + ui->m_settingsWidget->OnSetSettingsNode(m_SettingsNode, true); + InitImageStream(); + m_CombinedModality = ui->m_CombinedModalityCreationWidget->GetSelectedCombinedModality(); + ui->m_TargetMarkingWidget->SetCombinedModality(m_CombinedModality); + ui->m_TargetMarkingWidget->SetDataStorage(this->GetDataStorage()); + ui->m_TargetMarkingWidget->OnSettingsChanged(m_SettingsNode); + ui->m_TargetMarkingWidget->OnActivateStep(); + ui->m_TargetMarkingWidget->OnStartStep(); + ui->m_TargetMarkingWidget->Update(); + +} +void QmitkUSNavigationMarkerPlacement::OnInitializeCriticalStructureMarking() +{ + ui->m_CriticalStructuresWidget->SetCombinedModality(m_CombinedModality); + ui->m_CriticalStructuresWidget->SetDataStorage(this->GetDataStorage()); + ui->m_CriticalStructuresWidget->OnSettingsChanged(m_SettingsNode); + ui->m_CriticalStructuresWidget->OnActivateStep(); + ui->m_CriticalStructuresWidget->OnStartStep(); + ui->m_CriticalStructuresWidget->Update(); +} +void QmitkUSNavigationMarkerPlacement::OnInitializeNavigation() +{ + ui->m_NavigationWidget->SetCombinedModality(m_CombinedModality); + ui->m_NavigationWidget->SetDataStorage(this->GetDataStorage()); + ui->m_NavigationWidget->OnSettingsChanged(m_SettingsNode); + ui->m_NavigationWidget->OnActivateStep(); + ui->m_NavigationWidget->OnStartStep(); + ui->m_NavigationWidget->Update(); + +} + +void QmitkUSNavigationMarkerPlacement::InitImageStream() +{ + if (m_ImageStreamNode.IsNull()) + { + m_ImageStreamNode = mitk::DataNode::New(); + m_ImageStreamNode->SetName("US Navigation Viewing Stream"); + this->GetDataStorage()->Add(m_ImageStreamNode); + } +} + void QmitkUSNavigationMarkerPlacement::OnCombinedModalityPropertyChanged(const std::string &key, const std::string &) { if (key == mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH) { m_ReinitAlreadyDone = false; this->ReinitOnImage(); if (m_CombinedModality.IsNotNull() && !m_CombinedModality->GetIsCalibratedForCurrentStatus()) { mitk::LayoutAnnotationRenderer::AddAnnotation( m_WarnOverlay.GetPointer(), "stdmulti.widget1", mitk::LayoutAnnotationRenderer::TopLeft); MITK_WARN << "No calibration available for the selected ultrasound image depth."; } } } void QmitkUSNavigationMarkerPlacement::SetFocus() { this->ReinitOnImage(); } void QmitkUSNavigationMarkerPlacement::OnTimeout() { + if (m_CombinedModality.IsNull()) return; + m_CombinedModality->Modified(); //shouldn't be nessecary ... fix in abstract ultrasound tracker device! + m_CombinedModality->Update(); + ui->m_TargetMarkingWidget->Update(); + ui->m_CriticalStructuresWidget->Update(); + ui->m_NavigationWidget->Update(); + + mitk::Image::Pointer image = m_CombinedModality->GetOutput(); + // make sure that always the current image is set to the data node + if (image.IsNotNull() && m_ImageStreamNode->GetData() != image.GetPointer() && image->IsInitialized()) + { + m_ImageStreamNode->SetData(image); + } + if (!m_StdMultiWidget) { // try to get the standard multi widget if it couldn't be got before mitk::IRenderWindowPart *renderWindow = this->GetRenderWindowPart(); QmitkStdMultiWidgetEditor *multiWidgetEditor = dynamic_cast(renderWindow); // if there is a standard multi widget now, disable the level window and // change the layout to 2D up and 3d down if (multiWidgetEditor) { m_StdMultiWidget = multiWidgetEditor->GetStdMultiWidget(); SetTwoWindowView(); } this->CreateOverlays(); } if (m_CombinedModality.IsNotNull() && - !this->m_CombinedModality->GetIsFreezed()) // if the combined modality is freezed: do nothing + !this->m_CombinedModality->GetUltrasoundDevice()->GetIsFreezed()) // if the combined modality is freezed: do nothing { ui->navigationProcessWidget->UpdateNavigationProgress(); m_AblationZonesDisplacementFilter->Update(); + + // update the 3D window only every fourth time to speed up the rendering (at least in 2D) this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); // make sure that a reinit was performed on the image this->ReinitOnImage(); } } void QmitkUSNavigationMarkerPlacement::OnEnableNavigationLayout() { MITK_INFO << "Navigation Layout"; // try to get the standard multi widget if it couldn't be got before mitk::IRenderWindowPart *renderWindow = this->GetRenderWindowPart(); QmitkStdMultiWidgetEditor *multiWidgetEditor = dynamic_cast(renderWindow); // if there is a standard multi widget now, disable the level window and // change the layout to 2D up and 3d down if (multiWidgetEditor) { m_StdMultiWidget = multiWidgetEditor->GetStdMultiWidget(); SetTwoWindowView(); } } void QmitkUSNavigationMarkerPlacement::OnRenderWindowSelection() { SetTwoWindowView(); } void QmitkUSNavigationMarkerPlacement::OnRefreshView() { if (!ui->m_enableNavigationLayout->isChecked()) OnResetStandardLayout(); else { //Reinit the US Image Stream (this might be broken if there was a global reinit somewhere...) try { mitk::RenderingManager::GetInstance()->InitializeViews(//Reinit this->GetDataStorage()//GetDataStorage ->GetNamedNode("US Support Viewing Stream")->GetData()->GetTimeGeometry());//GetNode } catch (...) { MITK_DEBUG << "No reinit possible"; } SetTwoWindowView(); } } void QmitkUSNavigationMarkerPlacement::SetTwoWindowView() { if (m_StdMultiWidget) { m_StdMultiWidget->DisableStandardLevelWindow(); int i, j, k; switch (this->ui->m_RenderWindowSelection->value()) { case 1: mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))->GetCameraController()->SetViewToCaudal(); i = 2; j = 3; //other windows k = 1; break; case 2: mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))->GetCameraController()->SetViewToSinister(); i = 1; j = 3; k = 2; break; case 3: mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))->GetCameraController()->SetViewToAnterior(); i = 2; j = 1; k = 3; break; default: return; } m_StdMultiWidget->changeLayoutTo2DUpAnd3DDown(k); ////Crosshair invisible in 3D view this->GetDataStorage()->GetNamedNode("stdmulti.widget" + std::to_string(i) + ".plane")-> SetBoolProperty("visible", false, mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); this->GetDataStorage()->GetNamedNode("stdmulti.widget" + std::to_string(j) + ".plane")-> SetBoolProperty("visible", false, mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); this->GetDataStorage()->GetNamedNode("stdmulti.widget" + std::to_string(k) + ".plane")-> SetBoolProperty("visible", true, mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); this->GetDataStorage()->GetNamedNode("stdmulti.widget" + std::to_string(i) + ".plane")-> SetIntProperty("Crosshair.Gap Size", 0); this->GetDataStorage()->GetNamedNode("stdmulti.widget" + std::to_string(j) + ".plane")-> SetIntProperty("Crosshair.Gap Size", 0); } } void QmitkUSNavigationMarkerPlacement::OnResetStandardLayout() { //reset render windows mitk::DataNode::Pointer widget1 = this->GetDataStorage()->GetNamedNode("stdmulti.widget1.plane"); if (widget1.IsNotNull()) { widget1->SetVisibility(true); } mitk::DataNode::Pointer widget2 = this->GetDataStorage()->GetNamedNode("stdmulti.widget2.plane"); if (widget2.IsNotNull()) { widget2->SetVisibility(true); } mitk::DataNode::Pointer widget3 = this->GetDataStorage()->GetNamedNode("stdmulti.widget3.plane"); if (widget3.IsNotNull()) { widget3->SetVisibility(true); } m_StdMultiWidget->changeLayoutToDefault(); } void QmitkUSNavigationMarkerPlacement::OnChangeLayoutClicked() { if (ui->m_enableNavigationLayout->isChecked()) OnEnableNavigationLayout(); else OnResetStandardLayout(); } void QmitkUSNavigationMarkerPlacement::OnImageAndNavigationDataLoggingTimeout() { // update filter for logging navigation data and ultrasound images if (m_CombinedModality.IsNotNull()) { m_NavigationDataRecorder->Update(); // get last messages for logging filer and store them std::vector messages = m_LoggingBackend.GetNavigationMessages(); std::string composedMessage = ""; for (std::size_t i = 0; i < messages.size(); i++) { composedMessage += messages.at(i); } m_USImageLoggingFilter->AddMessageToCurrentImage(composedMessage); m_LoggingBackend.ClearNavigationMessages(); // update logging filter m_USImageLoggingFilter->Update(); } } void QmitkUSNavigationMarkerPlacement::OnStartExperiment() { // get name for the experiment by a QInputDialog bool ok; if (m_ExperimentName.isEmpty()) { // default: current date m_ExperimentName = QString::number(QDateTime::currentDateTime().date().year()) + "_" + QString::number(QDateTime::currentDateTime().date().month()) + "_" + QString::number(QDateTime::currentDateTime().date().day()) + "_experiment_" + QString::number(QDateTime::currentDateTime().time().hour()) + "." + QString::number(QDateTime::currentDateTime().time().minute()); } m_ExperimentName = QInputDialog::getText( m_Parent, QString("Experiment Name"), QString("Name of the Experiment"), QLineEdit::Normal, m_ExperimentName, &ok); MITK_INFO("USNavigationLogging") << "Experiment started: " << m_ExperimentName.toStdString(); if (ok && !m_ExperimentName.isEmpty()) { // display error message and call the function recursivly if a directory // with the given name already exists QDir experimentResultsDir(m_ResultsDirectory + QDir::separator() + m_ExperimentName); if (experimentResultsDir.exists()) { QMessageBox::critical( m_Parent, "Results Directory Exists", "The result directory already exists.\nPlease choose an other name."); this->OnStartExperiment(); } else { QDir(m_ResultsDirectory).mkdir(m_ExperimentName); m_ExperimentResultsSubDirectory = m_ResultsDirectory + QDir::separator() + m_ExperimentName; // experiment is running now ui->runningLabel->setPixmap(m_IconRunning); ui->navigationProcessWidget->EnableInteraction(true); // (re)start timer for navigation step durations m_NavigationStepTimer->Reset(); m_NavigationStepTimer->SetOutputFileName( QString(m_ExperimentResultsSubDirectory + QDir::separator() + QString("durations.cvs")).toStdString()); - m_NavigationStepTimer->SetActiveIndex(0, m_NavigationSteps.at(0)->GetTitle().toStdString()); + m_NavigationStepTimer->SetActiveIndex(0, "Initialization"); ui->finishExperimentButton->setEnabled(true); ui->startExperimentButton->setDisabled(true); // initialize and register logging backend QString loggingFilename = m_ExperimentResultsSubDirectory + QDir::separator() + "logging.txt"; m_LoggingBackend.SetOutputFileName(loggingFilename.toStdString()); mbilog::RegisterBackend(&m_LoggingBackend); // initialize and start navigation data recorder form xml recording m_NavigationDataRecorder->StartRecording(); m_IsExperimentRunning = true; m_ImageAndNavigationDataLoggingTimer->start(1000); // (re)start experiment logging and set output file name m_ExperimentLogging->Reset(); m_ExperimentLogging->SetFileName( QString(m_ExperimentResultsSubDirectory + QDir::separator() + "experiment-logging.xml").toStdString()); } } } void QmitkUSNavigationMarkerPlacement::OnFinishExperiment() { this->WaitCursorOn(); MITK_INFO("USNavigationLogging") << "Experiment finished!"; MITK_INFO("USNavigationLogging") << "Position/Orientation of needle tip: " - << (dynamic_cast(m_CombinedModality->GetTrackingDevice()->GetOutput(0)))->GetPosition(); + << (dynamic_cast(m_CombinedModality->GetTrackingDeviceDataSource()->GetOutput(0)))->GetPosition(); MITK_INFO("USNavigationLogging") << "Position of target: " << m_TargetNodeDisplacementFilter->GetRawDisplacementNavigationData(0)->GetPosition(); MITK_INFO("USNavigationLogging") << "Total duration: " << m_NavigationStepTimer->GetTotalDuration(); ui->navigationProcessWidget->FinishCurrentNavigationStep(); m_ImageAndNavigationDataLoggingTimer->stop(); ui->runningLabel->setPixmap(m_IconNotRunning); ui->navigationProcessWidget->EnableInteraction(false); m_NavigationStepTimer->Stop(); // make sure that the navigation process will be start from beginning at the // next experiment ui->navigationProcessWidget->ResetNavigationProcess(); ui->finishExperimentButton->setDisabled(true); ui->startExperimentButton->setEnabled(true); MITK_INFO("USNavigationLogging") << "Writing logging data to " << m_ExperimentResultsSubDirectory.toStdString(); // save ultrasound images to the file system QDir(m_ExperimentResultsSubDirectory).mkdir("ImageStream"); m_USImageLoggingFilter->Update(); m_USImageLoggingFilter->SetImageFilesExtension(".jpg"); m_USImageLoggingFilter->SaveImages( QString(m_ExperimentResultsSubDirectory + QDir::separator() + "ImageStream" + QDir::separator()).toStdString()); m_USImageLoggingFilter = mitk::USImageLoggingFilter::New(); m_NavigationDataRecorder->StopRecording(); // Write data to csv and xml file mitk::IOUtil::Save( m_NavigationDataRecorder->GetNavigationDataSet(), (QString(m_ExperimentResultsSubDirectory + QDir::separator() + "navigation-data.xml").toStdString().c_str())); mitk::IOUtil::Save( m_NavigationDataRecorder->GetNavigationDataSet(), (QString(m_ExperimentResultsSubDirectory + QDir::separator() + "navigation-data.csv").toStdString().c_str())); // write logged navigation data messages to separate file std::stringstream csvNavigationMessagesFilename; csvNavigationMessagesFilename << m_ExperimentResultsSubDirectory.toStdString() << QDir::separator().toLatin1() << "CSVNavigationMessagesLogFile.csv"; MITK_INFO("USNavigationLogging") << "Writing logged navigation messages to separate csv file: " << csvNavigationMessagesFilename.str(); m_LoggingBackend.WriteCSVFileWithNavigationMessages(csvNavigationMessagesFilename.str()); mbilog::UnregisterBackend(&m_LoggingBackend); m_IsExperimentRunning = false; m_ImageAndNavigationDataLoggingTimer->stop(); m_CombinedModality = nullptr; // reset scene number for next experiment m_SceneNumber = 1; this->WaitCursorOff(); MITK_INFO("USNavigationLogging") << "Finished!"; } -void QmitkUSNavigationMarkerPlacement::OnCombinedModalityChanged( - itk::SmartPointer combinedModality) -{ - // remove old listener for ultrasound device changes - if (m_CombinedModality.IsNotNull() && m_CombinedModality->GetUltrasoundDevice().IsNotNull()) - { - m_CombinedModality->GetUltrasoundDevice()->RemovePropertyChangedListener(m_ListenerDeviceChanged); - } - - m_CombinedModality = combinedModality; - m_ReinitAlreadyDone = false; - - // add a listener for ultrasound device changes - if (m_CombinedModality.IsNotNull() && m_CombinedModality->GetUltrasoundDevice().IsNotNull()) - { - m_CombinedModality->GetUltrasoundDevice()->AddPropertyChangedListener(m_ListenerDeviceChanged); - } - - // update navigation data recorder for using the new combined modality - mitk::NavigationDataSource::Pointer navigationDataSource = combinedModality->GetNavigationDataSource(); - m_NavigationDataRecorder->ConnectTo(navigationDataSource); - m_NavigationDataRecorder->ResetRecording(); - - // update ultrasound image logging filter for using the new combined modality - mitk::USDevice::Pointer ultrasoundImageSource = combinedModality->GetUltrasoundDevice(); - for (unsigned int n = 0; n < ultrasoundImageSource->GetNumberOfIndexedOutputs(); ++n) - { - m_USImageLoggingFilter->SetInput(n, ultrasoundImageSource->GetOutput(n)); - } - - // update ablation zone filter for using the new combined modality - for (unsigned int n = 0; n < navigationDataSource->GetNumberOfIndexedOutputs(); ++n) - { - m_AblationZonesDisplacementFilter->SetInput(n, navigationDataSource->GetOutput(n)); - } - m_AblationZonesDisplacementFilter->SelectInput(m_MarkerIndex); - - // make sure that a reinit is done for the new images - this->ReinitOnImage(); -} - void QmitkUSNavigationMarkerPlacement::OnSettingsChanged(itk::SmartPointer settings) { - std::string applicationName; - if (!settings->GetStringProperty("settings.application", applicationName)) - { - // set default application if the string property is not available - applicationName = "Marker Placement"; - } - - // create navigation step widgets according to the selected application - if (applicationName != m_CurrentApplicationName) - { - m_CurrentApplicationName = applicationName; - - QmitkUSNavigationProcessWidget::NavigationStepVector navigationSteps; - if (applicationName == "Puncture") - { - QmitkUSNavigationStepCombinedModality* stepCombinedModality = - new QmitkUSNavigationStepCombinedModality(m_Parent); - QmitkUSNavigationStepTumourSelection* stepTumourSelection = - new QmitkUSNavigationStepTumourSelection(m_Parent); - stepTumourSelection->SetTargetSelectionOptional(true); - m_TargetNodeDisplacementFilter = stepTumourSelection->GetTumourNodeDisplacementFilter(); - QmitkUSNavigationStepZoneMarking* stepZoneMarking = - new QmitkUSNavigationStepZoneMarking(m_Parent); - QmitkUSNavigationStepPunctuationIntervention* stepIntervention = - new QmitkUSNavigationStepPunctuationIntervention(m_Parent); - - connect(stepIntervention, SIGNAL(AddAblationZoneClicked(int)), this, SLOT(OnAddAblationZone(int))); - connect(stepIntervention, SIGNAL(AblationZoneChanged(int, int)), this, SLOT(OnChangeAblationZone(int, int))); - - m_NavigationStepNames = std::vector(); - navigationSteps.push_back(stepCombinedModality); - m_NavigationStepNames.push_back("Combined Modality Initialization"); - navigationSteps.push_back(stepTumourSelection); - m_NavigationStepNames.push_back("Target Selection"); - navigationSteps.push_back(stepZoneMarking); - m_NavigationStepNames.push_back("Critical Structure Marking"); - navigationSteps.push_back(stepIntervention); - m_NavigationStepNames.push_back("Intervention"); - } - else if (applicationName == "Marker Placement") - { - QmitkUSNavigationStepCombinedModality *stepCombinedModality = new QmitkUSNavigationStepCombinedModality(m_Parent); - QmitkUSNavigationStepTumourSelection *stepTumourSelection = new QmitkUSNavigationStepTumourSelection(m_Parent); - m_TargetNodeDisplacementFilter = stepTumourSelection->GetTumourNodeDisplacementFilter(); - QmitkUSNavigationStepZoneMarking *stepZoneMarking = new QmitkUSNavigationStepZoneMarking(m_Parent); - QmitkUSNavigationStepPlacementPlanning *stepPlacementPlanning = - new QmitkUSNavigationStepPlacementPlanning(m_Parent); - QmitkUSNavigationStepMarkerIntervention *stepMarkerIntervention = - new QmitkUSNavigationStepMarkerIntervention(m_Parent); - - m_NavigationStepNames = std::vector(); - navigationSteps.push_back(stepCombinedModality); - m_NavigationStepNames.push_back("Combined Modality Initialization"); - navigationSteps.push_back(stepTumourSelection); - m_NavigationStepNames.push_back("Target Selection"); - navigationSteps.push_back(stepZoneMarking); - m_NavigationStepNames.push_back("Critical Structure Marking"); - navigationSteps.push_back(stepPlacementPlanning); - m_NavigationStepNames.push_back("Placement Planning"); - navigationSteps.push_back(stepMarkerIntervention); - m_NavigationStepNames.push_back("Marker Intervention"); - } - - // set navigation step widgets to the process widget - ui->navigationProcessWidget->SetNavigationSteps(navigationSteps); - - for (QmitkUSNavigationProcessWidget::NavigationStepIterator it = m_NavigationSteps.begin(); - it != m_NavigationSteps.end(); - ++it) - { - delete *it; - } - m_NavigationSteps.clear(); - m_NavigationSteps = navigationSteps; - } - // initialize gui according to the experiment mode setting bool experimentMode = false; settings->GetBoolProperty("settings.experiment-mode", experimentMode); ui->startExperimentButton->setVisible(experimentMode); ui->finishExperimentButton->setVisible(experimentMode); ui->runningLabel->setVisible(experimentMode); if (experimentMode && !m_IsExperimentRunning) { ui->navigationProcessWidget->ResetNavigationProcess(); ui->navigationProcessWidget->EnableInteraction(false); ui->runningLabel->setPixmap(m_IconNotRunning); } else if (!experimentMode) { if (m_IsExperimentRunning) { this->OnFinishExperiment(); } ui->navigationProcessWidget->EnableInteraction(true); } // get the results directory from the settings and use home directory if // there is no results directory configured std::string resultsDirectory; if (settings->GetStringProperty("settings.experiment-results-directory", resultsDirectory)) { m_ResultsDirectory = QString::fromStdString(resultsDirectory); } else { m_ResultsDirectory = QDir::homePath(); } // make sure that the results directory exists QDir resultsDirectoryQDir = QDir(m_ResultsDirectory); if (!resultsDirectoryQDir.exists()) { resultsDirectoryQDir.mkpath(m_ResultsDirectory); } MITK_INFO("USNavigation") << "Results Directory: " << m_ResultsDirectory.toStdString(); } -void QmitkUSNavigationMarkerPlacement::OnActiveNavigationStepChanged(int index) -{ - // update navigation step timer each time the active navigation step changes - m_NavigationStepTimer->SetActiveIndex(index, m_NavigationSteps.at(index)->GetTitle().toStdString()); - if (static_cast(m_NavigationStepNames.size()) <= index) - { - MITK_INFO("USNavigationLogging") << "Someting went wrong: unknown navigation step!"; - } - else - { - MITK_INFO("USNavigationLogging") << "Navigation step finished/changed, next step: " - << this->m_NavigationStepNames.at(index).toStdString() - << "; duration until now: " << m_NavigationStepTimer->GetTotalDuration(); - } -} - -void QmitkUSNavigationMarkerPlacement::OnNextNavigationStepInitialization(int index) -{ - MITK_DEBUG << "Next Step: " << m_NavigationSteps.at(index)->GetTitle().toStdString(); - - if (m_NavigationSteps.at(index)->GetTitle().toStdString() == "Computer-assisted Intervention") - { - QmitkUSNavigationStepPunctuationIntervention* navigationStepPunctuationIntervention = static_cast(m_NavigationSteps.at(index)); - if (navigationStepPunctuationIntervention != nullptr) - { - if (m_CurrentStorage.IsNull()) { this->UpdateToolStorage(); } - if (m_CurrentStorage.IsNull() || (m_CurrentStorage->GetTool(m_NeedleIndex).IsNull())) - { - MITK_WARN << "Found null pointer when setting the tool axis, aborting"; - } - else - { - navigationStepPunctuationIntervention->SetNeedleMetaData(m_CurrentStorage->GetTool(m_NeedleIndex)); - MITK_DEBUG << "Needle axis vector: " << m_CurrentStorage->GetTool(m_NeedleIndex)->GetToolAxis(); - } - } - } -} - -void QmitkUSNavigationMarkerPlacement::OnIntermediateResultProduced(const itk::SmartPointer resultsNode) -{ - // intermediate results only matter during an experiment - if (!m_IsExperimentRunning) - { - return; - } - - this->WaitCursorOn(); - - // set results node to the experiment logging (for saving contents to the - // file system) - m_ExperimentLogging->SetResult(resultsNode); - - std::string resultsName; - if (!resultsNode->GetName(resultsName)) - { - MITK_WARN << "Could not get name of current results node."; - return; - } - - // save the mitk scene - std::string scenefile = QString(m_ExperimentResultsSubDirectory + QDir::separator() + - QString("Scene %1 - ").arg(m_SceneNumber++, 2, 10, QChar('0')) + - QString::fromStdString(resultsName).replace(":", "_") + ".mitk") - .toStdString(); - MITK_INFO << "Saving Scene File: " << scenefile; - - mitk::SceneIO::Pointer sceneIO = mitk::SceneIO::New(); - mitk::NodePredicateNot::Pointer isNotHelperObject = - mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true))); - mitk::DataStorage::SetOfObjects::ConstPointer nodesToBeSaved = this->GetDataStorage()->GetSubset(isNotHelperObject); - - this->Convert2DImagesTo3D(nodesToBeSaved); - - sceneIO->SaveScene(nodesToBeSaved, this->GetDataStorage(), scenefile); - - this->WaitCursorOff(); -} - void QmitkUSNavigationMarkerPlacement::ReinitOnImage() { if (!m_ReinitAlreadyDone && m_CombinedModality.IsNotNull()) { // make sure that the output is already calibrated correctly // (if the zoom level was changed recently) m_CombinedModality->Modified(); m_CombinedModality->Update(); mitk::Image::Pointer image = m_CombinedModality->GetOutput(); if (image.IsNotNull() && image->IsInitialized()) { // make a reinit on the ultrasound image mitk::IRenderWindowPart *renderWindow = this->GetRenderWindowPart(); if (renderWindow != NULL && image->GetTimeGeometry()->IsValid()) { renderWindow->GetRenderingManager()->InitializeViews( image->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); renderWindow->GetRenderingManager()->RequestUpdateAll(); } this->RequestRenderWindowUpdate(); m_ReinitAlreadyDone = true; } } } void QmitkUSNavigationMarkerPlacement::Convert2DImagesTo3D(mitk::DataStorage::SetOfObjects::ConstPointer nodes) { for (mitk::DataStorage::SetOfObjects::ConstIterator it = nodes->Begin(); it != nodes->End(); ++it) { if (it->Value()->GetData() && strcmp(it->Value()->GetData()->GetNameOfClass(), "Image") == 0) { // convert image to 3d image if it is 2d at the moment mitk::Image::Pointer image = dynamic_cast(it->Value()->GetData()); if (image.IsNotNull() && image->GetDimension() == 2 && !image->GetGeometry()->Is2DConvertable()) { mitk::Convert2Dto3DImageFilter::Pointer convert2DTo3DImageFilter = mitk::Convert2Dto3DImageFilter::New(); convert2DTo3DImageFilter->SetInput(image); convert2DTo3DImageFilter->Update(); it->Value()->SetData(convert2DTo3DImageFilter->GetOutput()); } } } } void QmitkUSNavigationMarkerPlacement::CreateOverlays() { // initialize warning overlay (and do not display it, yet) m_WarnOverlay->SetText("Warning: No calibration available for current depth."); // set position and font size for the text overlay // (nonesense postition as a layouter is used, but it ignored // the overlay without setting a position here) mitk::Point2D overlayPosition; overlayPosition.SetElement(0, -50.0f); overlayPosition.SetElement(1, -50.0f); m_WarnOverlay->SetPosition2D(overlayPosition); m_WarnOverlay->SetFontSize(22); m_WarnOverlay->SetColor(1, 0, 0); // overlay should be red } void QmitkUSNavigationMarkerPlacement::UpdateToolStorage() { if (m_NavigationDataSource.IsNull()) { m_NavigationDataSource = m_CombinedModality->GetNavigationDataSource(); } if (m_NavigationDataSource.IsNull()) { MITK_WARN << "Found an invalid navigation data source object!"; } us::ModuleContext* context = us::GetModuleContext(); std::string id = m_NavigationDataSource->US_PROPKEY_ID; std::string filter = "(" + mitk::NavigationToolStorage::US_PROPKEY_SOURCE_ID + "=" + id + ")"; // Get Storage std::vector > refs = context->GetServiceReferences(); m_CurrentStorage = context->GetService(refs.front()); if (m_CurrentStorage.IsNull()) { MITK_WARN << "Found an invalid storage object!"; } else if (m_CurrentStorage->GetToolCount() != m_NavigationDataSource->GetNumberOfOutputs()) //there is something wrong with the storage { MITK_WARN << "Found a tool storage, but it has not the same number of tools like the NavigationDataSource. This storage won't be used because it isn't the right one."; m_CurrentStorage = NULL; } } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationMarkerPlacement.h b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationMarkerPlacement.h index e4e4634543..7f2623d38f 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationMarkerPlacement.h +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationMarkerPlacement.h @@ -1,216 +1,208 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkUSNAVIGATIONMARKERPLACEMENT_H #define QmitkUSNAVIGATIONMARKERPLACEMENT_H #include #include "IO/mitkUSNavigationLoggingBackend.h" #include "Widgets/QmitkUSNavigationProcessWidget.h" #include "mitkNavigationDataRecorder.h" #include "mitkNodeDisplacementFilter.h" #include "mitkUSImageLoggingFilter.h" #include #include -#include +#include #include namespace itk { template class SmartPointer; } namespace mitk { class USNavigationStepTimer; class USNavigationExperimentLogging; } namespace Ui { class QmitkUSNavigationMarkerPlacement; } class QmitkUSAbstractNavigationStep; class QmitkUSNavigationStepPunctuationIntervention; class QmitkStdMultiWidget; class QTimer; class QSignalMapper; /** * \brief View for navigated marker placement using the combined modality. * This view utilizes the QmitkUSNavigationProcessWidget to do the navigation * process. It can be switched between widgets for marker placement and widgets * for punctuation. * * An experiment mode allows for logging results, durations and the ultrasound * images. */ class QmitkUSNavigationMarkerPlacement : public QmitkAbstractView { Q_OBJECT protected slots: + + void OnInitializeTargetMarking(); + void OnInitializeCriticalStructureMarking(); + void OnInitializeNavigation(); + /** * \brief Called periodically to update the rendering. * The standard multi widget is changed to fit the navigation process once it * is available and a reinit on the ultrasound image is done for a new image * node. */ void OnTimeout(); /** * \brief Called periodically during an experiment for logging the ultrasound images. */ void OnImageAndNavigationDataLoggingTimeout(); /** * \brief Initializes anything neccessary for an experiment. * The user is asked for a directory for storing the results and the logging * is started. */ void OnStartExperiment(); /** * \brief Stops logging and saves everything to the file system. */ void OnFinishExperiment(); - void OnCombinedModalityChanged(itk::SmartPointer); - /** * \brief Switches the navigation step widgets if the navigation application was changed. */ void OnSettingsChanged(itk::SmartPointer); - /** - * \brief Updates the timer for the navigation steps durations every time the active navigation step changes. - */ - void OnActiveNavigationStepChanged(int); - - /** Initializes the next navigation step */ - void OnNextNavigationStepInitialization(int); - - /** - * \brief The data node is given to the experiment logging and scene is saved to the file system. - */ - void OnIntermediateResultProduced(const itk::SmartPointer); - void OnAddAblationZone(int size); void OnEnableNavigationLayout(); void OnResetStandardLayout(); void OnChangeLayoutClicked(); void OnChangeAblationZone(int id, int newSize); void OnRenderWindowSelection(); void OnRefreshView(); public: static const char *DATANAME_TUMOUR; static const char *DATANAME_TARGETSURFACE; static const char *DATANAME_ZONES; static const char *DATANAME_TARGETS; static const char *DATANAME_TARGETS_PATHS; static const char *DATANAME_REACHED_TARGETS; explicit QmitkUSNavigationMarkerPlacement(); ~QmitkUSNavigationMarkerPlacement(); virtual void CreateQtPartControl(QWidget *parent); static const std::string VIEW_ID; void OnCombinedModalityPropertyChanged(const std::string &, const std::string &); protected: /** * \brief A reinit on the ultrasound image is performed every time the view gets the focus. */ virtual void SetFocus(); /** * \brief Helper function which performs a reinit on the ultrasound image. */ void ReinitOnImage(); /** * \brief Sets the multiwidget to two windows, axial on top and 3D render window on the bottom. */ virtual void SetTwoWindowView(); /** * \brief Helper function for being able to serialize the 2d ultrasound image. */ void Convert2DImagesTo3D(mitk::DataStorage::SetOfObjects::ConstPointer nodes); void UpdateToolStorage(); void CreateOverlays(); + void InitImageStream(); + QWidget *m_Parent; - QmitkUSNavigationProcessWidget::NavigationStepVector m_NavigationSteps; QTimer *m_UpdateTimer; QTimer *m_ImageAndNavigationDataLoggingTimer; QmitkStdMultiWidget *m_StdMultiWidget; - itk::SmartPointer m_CombinedModality; + itk::SmartPointer m_CombinedModality; + itk::SmartPointer m_SettingsNode; bool m_ReinitAlreadyDone; bool m_IsExperimentRunning; std::string m_CurrentApplicationName; itk::SmartPointer m_NavigationStepTimer; itk::SmartPointer m_ExperimentLogging; QPixmap m_IconRunning; QPixmap m_IconNotRunning; QString m_ResultsDirectory; QString m_ExperimentName; QString m_ExperimentResultsSubDirectory; std::vector m_NavigationStepNames; // stores the names of the navigation steps which are currently used (for logging purposes) mitk::USNavigationLoggingBackend m_LoggingBackend; mitk::USImageLoggingFilter::Pointer m_USImageLoggingFilter; mitk::NavigationDataRecorder::Pointer m_NavigationDataRecorder; // records navigation data files mitk::NodeDisplacementFilter::Pointer m_TargetNodeDisplacementFilter; mitk::NodeDisplacementFilter::Pointer m_AblationZonesDisplacementFilter; std::vector m_AblationZonesVector; int m_NeedleIndex; int m_MarkerIndex; int m_SceneNumber; itk::SmartPointer m_WarnOverlay; //To get tool storage mitk::NavigationDataSource::Pointer m_NavigationDataSource; mitk::NavigationToolStorage::Pointer m_CurrentStorage; -private: - mitk::MessageDelegate2 m_ListenerDeviceChanged; + itk::SmartPointer m_ImageStreamNode; +private: Ui::QmitkUSNavigationMarkerPlacement *ui; }; #endif // USNAVIGATIONMARKERPLACEMENT_H diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationMarkerPlacement.ui b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationMarkerPlacement.ui index ceb1ffc701..e6ad0988cf 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationMarkerPlacement.ui +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationMarkerPlacement.ui @@ -1,123 +1,249 @@ QmitkUSNavigationMarkerPlacement 0 0 - 443 - 146 + 878 + 745 Form - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - + - + + + 0 + + + + New + + + + + + 0 + + + + + 0 + 0 + 828 + 408 + + + + Initialization + + + + + + + + + + Target + + + + + + Initialize + + + + + + + + + + + Critical Structures + + + + + + Initialize + + + + + + + + + + + + 0 + 0 + 828 + 408 + + + + Navigation + + + + + + Initialize + + + + + + + + + + + + + + + Old + + + + + + + + + + Settings + + + + + + + + + + + + + + 20 + 20 + + + + + + Qt::Horizontal Enable Navigation Render Window Layout with RenderWindow true 1 3 Refresh view - - - - - Start New Experiment - - - - - - - false - - - Finish Experiment - - - - - - - - 20 - 20 - - - - - - - - + + + false + + + Finish Experiment + + + + + + + Start New Experiment + + QmitkUSNavigationProcessWidget QWidget
src/internal/Widgets/QmitkUSNavigationProcessWidget.h
1
+ + QmitkUSNavigationStepCombinedModality + QWidget +
src/internal/NavigationStepWidgets/QmitkUSNavigationStepCombinedModality.h
+ 1 +
+ + QmitkUSNavigationStepTumourSelection + QWidget +
src/internal/NavigationStepWidgets/QmitkUSNavigationStepTumourSelection.h
+ 1 +
+ + QmitkUSNavigationStepZoneMarking + QWidget +
src/internal/NavigationStepWidgets/QmitkUSNavigationStepZoneMarking.h
+ 1 +
+ + QmitkUSNavigationStepPunctuationIntervention + QWidget +
src/internal/NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.h
+ 1 +
+ + QmitkUSNavigationCombinedSettingsWidget + QWidget +
src/internal/SettingsWidgets/QmitkUSNavigationCombinedSettingsWidget.h
+ 1 +
OnStartExperiment() OnFinishExperiment()
diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUltrasoundCalibration.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUltrasoundCalibration.cpp index 40fb72b2ab..149c3c1f42 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUltrasoundCalibration.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUltrasoundCalibration.cpp @@ -1,1140 +1,1141 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkUltrasoundCalibration.h" #include // Qt #include #include #include #include // MITK #include //#include #include #include #include #include #include #include "mitkIRenderingManager.h" // us #include //VTK #include #include #include #include #include #include #include "internal/org_mbi_gui_qt_usnavigation_Activator.h" //sleep headers #include #include const std::string QmitkUltrasoundCalibration::VIEW_ID = "org.mitk.views.ultrasoundcalibration"; QmitkUltrasoundCalibration::QmitkUltrasoundCalibration() : m_USDeviceChanged(this, &QmitkUltrasoundCalibration::OnUSDepthChanged) { ctkPluginContext* pluginContext = mitk::PluginActivator::GetContext(); if (pluginContext) { // to be notified about service event of an USDevice pluginContext->connectServiceListener(this, "OnDeciveServiceEvent", QString::fromStdString("(" + us::ServiceConstants::OBJECTCLASS() + "=" + us_service_interface_iid() + ")")); } } QmitkUltrasoundCalibration::~QmitkUltrasoundCalibration() { m_Controls.m_CombinedModalityManagerWidget->blockSignals(true); - mitk::USCombinedModality::Pointer combinedModality; + mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality; combinedModality = m_Controls.m_CombinedModalityManagerWidget->GetSelectedCombinedModality(); if (combinedModality.IsNotNull()) { combinedModality->GetUltrasoundDevice()->RemovePropertyChangedListener(m_USDeviceChanged); } m_Timer->stop(); // Sleep(500); //This might be problematic... seems like sometimes some ressources are still in use at calling time. this->OnStopCalibrationProcess(); this->OnStopPlusCalibration(); /*mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode("Tool Calibration Points"); if (node.IsNotNull())this->GetDataStorage()->Remove(node); node = this->GetDataStorage()->GetNamedNode("Image Calibration Points"); if (node.IsNotNull())this->GetDataStorage()->Remove(node); node = this->GetDataStorage()->GetNamedNode("US Image Stream"); if (node.IsNotNull())this->GetDataStorage()->Remove(node);*/ mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode("Needle Path"); if (node.IsNotNull())this->GetDataStorage()->Remove(node); this->GetDataStorage()->Remove(m_VerificationReferencePointsDataNode); delete m_Timer; } void QmitkUltrasoundCalibration::SetFocus() { m_Controls.m_ToolBox->setFocus(); } void QmitkUltrasoundCalibration::CreateQtPartControl(QWidget *parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); m_Controls.m_CombinedModalityManagerWidget->SetCalibrationLoadedNecessary(false); m_Timer = new QTimer(this); m_StreamingTimer = new QTimer(this); m_Controls.m_SpacingBtnFreeze->setEnabled(true); m_Controls.m_SpacingAddPoint->setEnabled(false); m_Controls.m_CalculateSpacing->setEnabled(false); m_SpacingPointsCount = 0; m_SpacingPoints = mitk::PointSet::New(); m_SpacingNode = mitk::DataNode::New(); m_SpacingNode->SetName("Spacing Points"); m_SpacingNode->SetData(this->m_SpacingPoints); this->GetDataStorage()->Add(m_SpacingNode); // Pointset for Calibration Points m_CalibPointsTool = mitk::PointSet::New(); // Pointset for Worldpoints m_CalibPointsImage = mitk::PointSet::New(); m_CalibPointsCount = 0; // Evaluation Pointsets (Non-Visualized) m_EvalPointsImage = mitk::PointSet::New(); m_EvalPointsTool = mitk::PointSet::New(); m_EvalPointsProjected = mitk::PointSet::New(); // Neelde Projection Filter m_NeedleProjectionFilter = mitk::NeedleProjectionFilter::New(); // Tracking Status Widgets m_Controls.m_CalibTrackingStatus->ShowStatusLabels(); m_Controls.m_EvalTrackingStatus->ShowStatusLabels(); m_OverrideSpacing = false; // General & Device Selection connect(m_Timer, SIGNAL(timeout()), this, SLOT(Update())); //connect(m_Controls.m_ToolBox, SIGNAL(currentChanged(int)), this, SLOT(OnTabSwitch(int))); // Calibration connect(m_Controls.m_CalibBtnFreeze, SIGNAL(clicked()), this, SLOT(SwitchFreeze())); // Freeze connect(m_Controls.m_CalibBtnAddPoint, SIGNAL(clicked()), this, SLOT(OnAddCalibPoint())); // Tracking & Image Points (Calibration) connect(m_Controls.m_CalibBtnCalibrate, SIGNAL(clicked()), this, SLOT(OnCalibration())); // Perform Calibration // Evaluation connect(m_Controls.m_EvalBtnStep1, SIGNAL(clicked()), this, SLOT(OnAddEvalProjectedPoint())); // Needle Projection connect(m_Controls.m_EvalBtnStep2, SIGNAL(clicked()), this, SLOT(SwitchFreeze())); // Freeze connect(m_Controls.m_EvalBtnStep3, SIGNAL(clicked()), this, SLOT(OnAddEvalTargetPoint())); // Tracking & Image Points (Evaluation) connect(m_Controls.m_EvalBtnSave, SIGNAL(clicked()), this, SLOT(OnSaveEvaluation())); // Save Evaluation Results connect(m_Controls.m_CalibBtnSaveCalibration, SIGNAL(clicked()), this, SLOT(OnSaveCalibration())); // Save Evaluation Results connect(m_Controls.m_BtnReset, SIGNAL(clicked()), this, SLOT(OnReset())); // Reset Pointsets // PLUS Calibration connect(m_Controls.m_GetCalibrationFromPLUS, SIGNAL(clicked()), this, SLOT(OnGetPlusCalibration())); connect(m_Controls.m_StartStreaming, SIGNAL(clicked()), this, SLOT(OnStartStreaming())); connect(m_StreamingTimer, SIGNAL(timeout()), this, SLOT(OnStreamingTimerTimeout())); connect(m_Controls.m_StopPlusCalibration, SIGNAL(clicked()), this, SLOT(OnStopPlusCalibration())); connect(m_Controls.m_SavePlusCalibration, SIGNAL(clicked()), this, SLOT(OnSaveCalibration())); connect(this, SIGNAL(NewConnectionSignal()), this, SLOT(OnNewConnection())); //Determine Spacing for Calibration of USVideoDevice connect(m_Controls.m_SpacingBtnFreeze, SIGNAL(clicked()), this, SLOT(OnFreezeClicked())); connect(m_Controls.m_SpacingAddPoint, SIGNAL(clicked()), this, SLOT(OnAddSpacingPoint())); connect(m_Controls.m_CalculateSpacing, SIGNAL(clicked()), this, SLOT(OnCalculateSpacing())); //connect( m_Controls.m_CombinedModalityManagerWidget, SIGNAL(SignalCombinedModalitySelected(mitk::USCombinedModality::Pointer)), // this, SLOT(OnSelectDevice(mitk::USCombinedModality::Pointer)) ); connect(m_Controls.m_CombinedModalityManagerWidget, SIGNAL(SignalReadyForNextStep()), this, SLOT(OnDeviceSelected())); connect(m_Controls.m_CombinedModalityManagerWidget, SIGNAL(SignalNoLongerReadyForNextStep()), this, SLOT(OnDeviceDeselected())); connect(m_Controls.m_StartCalibrationButton, SIGNAL(clicked()), this, SLOT(OnStartCalibrationProcess())); connect(m_Controls.m_StartPlusCalibrationButton, SIGNAL(clicked()), this, SLOT(OnStartPlusCalibration())); connect(m_Controls.m_CalibBtnRestartCalibration, SIGNAL(clicked()), this, SLOT(OnReset())); connect(m_Controls.m_CalibBtnStopCalibration, SIGNAL(clicked()), this, SLOT(OnStopCalibrationProcess())); connect(m_Controls.m_AddReferencePoints, SIGNAL(clicked()), this, SLOT(OnAddCurrentTipPositionToReferencePoints())); connect(m_Controls.m_AddCurrentPointerTipForVerification, SIGNAL(clicked()), this, SLOT(OnAddCurrentTipPositionForVerification())); connect(m_Controls.m_StartVerification, SIGNAL(clicked()), this, SLOT(OnStartVerification())); //initialize data storage combo box m_Controls.m_ReferencePointsComboBox->SetDataStorage(this->GetDataStorage()); m_Controls.m_ReferencePointsComboBox->SetAutoSelectNewItems(true); m_Controls.m_ReferencePointsComboBox->SetPredicate(mitk::NodePredicateDataType::New("PointSet")); //initialize point list widget if (m_VerificationReferencePoints.IsNull()) { m_VerificationReferencePoints = mitk::PointSet::New(); } if (m_VerificationReferencePointsDataNode.IsNull()) { m_VerificationReferencePointsDataNode = mitk::DataNode::New(); m_VerificationReferencePointsDataNode->SetName("US Verification Reference Points"); m_VerificationReferencePointsDataNode->SetData(m_VerificationReferencePoints); this->GetDataStorage()->Add(m_VerificationReferencePointsDataNode); } m_Controls.m_ReferencePointsPointListWidget->SetPointSetNode(m_VerificationReferencePointsDataNode); m_Controls.m_ToolBox->setCurrentIndex(0); } void QmitkUltrasoundCalibration::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, const QList& /*nodes*/) { } void QmitkUltrasoundCalibration::OnTabSwitch(int index) { switch (index) { case 0: if (m_Controls.m_ToolBox->isItemEnabled(1) || m_Controls.m_ToolBox->isItemEnabled(2)) { this->OnStopCalibrationProcess(); } break; default: ; } } //void QmitkUltrasoundCalibration::OnSelectDevice(mitk::USCombinedModality::Pointer combinedModality) void QmitkUltrasoundCalibration::OnDeviceSelected() { - mitk::USCombinedModality::Pointer combinedModality; + mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality; combinedModality = m_Controls.m_CombinedModalityManagerWidget->GetSelectedCombinedModality(); if (combinedModality.IsNotNull()) { //m_Tracker = m_CombinedModality->GetNavigationDataSource(); // Construct Pipeline //this->m_NeedleProjectionFilter->SetInput(0, m_Tracker->GetOutput(0)); combinedModality->GetUltrasoundDevice()->AddPropertyChangedListener(m_USDeviceChanged); m_Controls.m_StartCalibrationButton->setEnabled(true); m_Controls.m_StartPlusCalibrationButton->setEnabled(true); m_Controls.m_ToolBox->setItemEnabled(1, true); m_Controls.m_ToolBox->setItemEnabled(2, true); } } void QmitkUltrasoundCalibration::OnDeviceDeselected() { - mitk::USCombinedModality::Pointer combinedModality; + mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality; combinedModality = m_Controls.m_CombinedModalityManagerWidget->GetSelectedCombinedModality(); if (combinedModality.IsNotNull()) { combinedModality->GetUltrasoundDevice()->RemovePropertyChangedListener(m_USDeviceChanged); } m_Controls.m_StartCalibrationButton->setEnabled(false); m_Controls.m_StartPlusCalibrationButton->setEnabled(false); m_Controls.m_ToolBox->setCurrentIndex(0); m_Controls.m_ToolBox->setItemEnabled(1, false); m_Controls.m_ToolBox->setItemEnabled(2, false); } void QmitkUltrasoundCalibration::OnAddCurrentTipPositionToReferencePoints() { if (m_Controls.m_VerificationPointerChoser->GetSelectedNavigationDataSource().IsNull() || (m_Controls.m_VerificationPointerChoser->GetSelectedToolID() == -1)) { MITK_WARN << "No tool selected, aborting"; return; } mitk::NavigationData::Pointer currentPointerData = m_Controls.m_VerificationPointerChoser->GetSelectedNavigationDataSource()->GetOutput(m_Controls.m_VerificationPointerChoser->GetSelectedToolID()); mitk::Point3D currentTipPosition = currentPointerData->GetPosition(); m_VerificationReferencePoints->InsertPoint(m_VerificationReferencePoints->GetSize(), currentTipPosition); } void QmitkUltrasoundCalibration::OnStartVerification() { m_currentPoint = 0; mitk::PointSet::Pointer selectedPointSet = dynamic_cast(m_Controls.m_ReferencePointsComboBox->GetSelectedNode()->GetData()); m_Controls.m_CurrentPointLabel->setText("Point " + QString::number(m_currentPoint) + " of " + QString::number(selectedPointSet->GetSize())); m_allErrors = std::vector(); m_allReferencePoints = std::vector(); for (int i = 0; i < selectedPointSet->GetSize(); i++) { m_allReferencePoints.push_back(selectedPointSet->GetPoint(i)); } } void QmitkUltrasoundCalibration::OnAddCurrentTipPositionForVerification() { if (m_currentPoint == -1) { MITK_WARN << "Cannot add point"; return; } if (m_Controls.m_VerificationPointerChoser->GetSelectedNavigationDataSource().IsNull() || (m_Controls.m_VerificationPointerChoser->GetSelectedToolID() == -1)) { MITK_WARN << "No tool selected, aborting"; return; } mitk::NavigationData::Pointer currentPointerData = m_Controls.m_VerificationPointerChoser->GetSelectedNavigationDataSource()->GetOutput(m_Controls.m_VerificationPointerChoser->GetSelectedToolID()); mitk::Point3D currentTipPosition = currentPointerData->GetPosition(); double currentError = m_allReferencePoints.at(m_currentPoint).EuclideanDistanceTo(currentTipPosition); MITK_INFO << "Current Error: " << currentError << " mm"; m_allErrors.push_back(currentError); if (++m_currentPoint < static_cast(m_allReferencePoints.size())) { m_Controls.m_CurrentPointLabel->setText("Point " + QString::number(m_currentPoint) + " of " + QString::number(m_allReferencePoints.size())); } else { m_currentPoint = -1; double meanError = 0; for (std::size_t i = 0; i < m_allErrors.size(); ++i) { meanError += m_allErrors[i]; } meanError /= m_allErrors.size(); QString result = "Finished verification! \n Verification of " + QString::number(m_allErrors.size()) + " points, mean error: " + QString::number(meanError) + " mm"; m_Controls.m_ResultsTextEdit->setText(result); MITK_INFO << result.toStdString(); } } void QmitkUltrasoundCalibration::OnStartCalibrationProcess() { // US Image Stream m_Node = mitk::DataNode::New(); m_Node->SetName("US Calibration Viewing Stream"); //create a dummy image (gray values 0..255) for correct initialization of level window, etc. mitk::Image::Pointer dummyImage = mitk::ImageGenerator::GenerateRandomImage(100, 100, 1, 1, 1, 1, 1, 255, 0); m_Node->SetData(dummyImage); this->GetDataStorage()->Add(m_Node); // data node for calibration point set m_CalibNode = mitk::DataNode::New(); m_CalibNode->SetName("Tool Calibration Points"); m_CalibNode->SetData(this->m_CalibPointsImage); this->GetDataStorage()->Add(m_CalibNode); // data node for world point set m_WorldNode = mitk::DataNode::New(); m_WorldNode->SetName("Image Calibration Points"); m_WorldNode->SetData(this->m_CalibPointsTool); this->GetDataStorage()->Add(m_WorldNode); m_CombinedModality = m_Controls.m_CombinedModalityManagerWidget->GetSelectedCombinedModality(); if (m_CombinedModality.IsNull()) { return; } m_Tracker = m_CombinedModality->GetNavigationDataSource(); //QString curDepth = service.getProperty(QString::fromStdString(mitk::USDevice::US_PROPKEY_BMODE_DEPTH)).toString(); // Construct Pipeline this->m_NeedleProjectionFilter->SetInput(0, m_Tracker->GetOutput(0)); QApplication::setOverrideCursor(Qt::WaitCursor); // make sure that the combined modality is in connected state before using it - if (m_CombinedModality->GetDeviceState() < mitk::USDevice::State_Connected) { m_CombinedModality->Connect(); } - if (m_CombinedModality->GetDeviceState() < mitk::USDevice::State_Activated) { m_CombinedModality->Activate(); } + if (m_CombinedModality->GetUltrasoundDevice()->GetDeviceState() < mitk::USDevice::State_Connected) { m_CombinedModality->GetUltrasoundDevice()->Connect(); } + if (m_CombinedModality->GetUltrasoundDevice()->GetDeviceState() < mitk::USDevice::State_Activated) { m_CombinedModality->GetUltrasoundDevice()->Activate(); } QApplication::restoreOverrideCursor(); this->SwitchFreeze(); // Todo: Maybe display this elsewhere this->ShowNeedlePath(); // Switch active tab to Calibration page m_Controls.m_ToolBox->setItemEnabled(1, true); m_Controls.m_ToolBox->setCurrentIndex(1); } void QmitkUltrasoundCalibration::OnStartPlusCalibration() { if (m_CombinedModality.IsNull()){ m_CombinedModality = m_Controls.m_CombinedModalityManagerWidget->GetSelectedCombinedModality(); if (m_CombinedModality.IsNull()) { return; } //something went wrong, there is no combined modality } //setup server to send UltrasoundImages to PLUS mitk::IGTLServer::Pointer m_USServer = mitk::IGTLServer::New(true); m_USServer->SetName("EchoTrack Image Source"); m_USServer->SetHostname("127.0.0.1"); m_USServer->SetPortNumber(18944); m_USMessageProvider = mitk::IGTLMessageProvider::New(); m_USMessageProvider->SetIGTLDevice(m_USServer); m_USMessageProvider->SetFPS(5); m_USImageToIGTLMessageFilter = mitk::ImageToIGTLMessageFilter::New(); m_USImageToIGTLMessageFilter->ConnectTo(m_CombinedModality->GetUltrasoundDevice()); m_USImageToIGTLMessageFilter->SetName("USImage Filter"); //setup server to send TrackingData to PLUS m_TrackingServer = mitk::IGTLServer::New(true); m_TrackingServer->SetName("EchoTrack Tracking Source"); m_TrackingServer->SetHostname("127.0.0.1"); m_TrackingServer->SetPortNumber(18945); m_TrackingMessageProvider = mitk::IGTLMessageProvider::New(); m_TrackingMessageProvider->SetIGTLDevice(m_TrackingServer); m_TrackingMessageProvider->SetFPS(5); m_TrackingToIGTLMessageFilter = mitk::NavigationDataToIGTLMessageFilter::New(); - m_TrackingToIGTLMessageFilter->ConnectTo(m_CombinedModality->GetTrackingDevice()); + m_TrackingToIGTLMessageFilter->ConnectTo(m_CombinedModality->GetTrackingDeviceDataSource()); m_TrackingToIGTLMessageFilter->SetName("Tracker Filter"); typedef itk::SimpleMemberCommand< QmitkUltrasoundCalibration > CurCommandType; CurCommandType::Pointer newConnectionCommand = CurCommandType::New(); newConnectionCommand->SetCallbackFunction( this, &QmitkUltrasoundCalibration::OnPlusConnected); this->m_NewConnectionObserverTag = this->m_TrackingServer->AddObserver( mitk::NewClientConnectionEvent(), newConnectionCommand); //Open connections of both servers if (m_USServer->OpenConnection()) { MITK_INFO << "US Server opened its connection successfully"; m_USServer->StartCommunication(); } else { MITK_INFO << "US Server could not open its connection"; } if (m_TrackingServer->OpenConnection()) { MITK_INFO << "Tracking Server opened its connection successfully"; m_TrackingServer->StartCommunication(); } else { MITK_INFO << "Tracking Server could not open its connection"; } if (m_USMessageProvider->IsCommunicating() && m_TrackingMessageProvider->IsCommunicating()) { m_Controls.m_StartPlusCalibrationButton->setEnabled(false); m_Controls.m_GetCalibrationFromPLUS->setEnabled(true); m_Controls.m_StartStreaming->setEnabled(false); m_Controls.m_SavePlusCalibration->setEnabled(false); m_Controls.m_SetupStatus->setStyleSheet("QLabel { color : green; }"); m_Controls.m_SetupStatus->setText("Setup successfull you can now connect PLUS"); } else { m_Controls.m_SetupStatus->setStyleSheet("QLabel { color : red; }"); m_Controls.m_SetupStatus->setText("Something went wrong. Please try again"); } } void QmitkUltrasoundCalibration::OnStopPlusCalibration() { //closing all server and clients when PlusCalibration is finished if (m_USMessageProvider.IsNotNull()) { if (m_USMessageProvider->IsStreaming()) { m_USMessageProvider->StopStreamingOfSource(m_USImageToIGTLMessageFilter); } } if (m_TrackingMessageProvider.IsNotNull()) { if (m_TrackingMessageProvider->IsStreaming()) { m_TrackingMessageProvider->StopStreamingOfSource(m_TrackingToIGTLMessageFilter); } } if (m_USServer.IsNotNull()) { m_USServer->CloseConnection(); } if (m_TrackingServer.IsNotNull()) { m_TrackingServer->CloseConnection(); } if (m_TransformClient.IsNotNull()) { m_TransformClient->CloseConnection(); } m_Controls.m_GotCalibrationLabel->setText(""); m_Controls.m_ConnectionStatus->setText(""); m_Controls.m_SetupStatus->setText(""); m_Controls.m_StartPlusCalibrationButton->setEnabled(true); m_StreamingTimer->stop(); delete m_StreamingTimer; } void QmitkUltrasoundCalibration::OnPlusConnected() { emit NewConnectionSignal(); } void QmitkUltrasoundCalibration::OnNewConnection() { m_Controls.m_StartStreaming->setEnabled(true); m_Controls.m_ConnectionStatus->setStyleSheet("QLabel { color : green; }"); m_Controls.m_ConnectionStatus->setText("Connection successfull you can now start streaming"); } void QmitkUltrasoundCalibration::OnStreamingTimerTimeout() { m_USMessageProvider->Update(); m_TrackingMessageProvider->Update(); } void QmitkUltrasoundCalibration::OnStartStreaming() { m_USMessageProvider->StartStreamingOfSource(m_USImageToIGTLMessageFilter, 5); m_TrackingMessageProvider->StartStreamingOfSource(m_TrackingToIGTLMessageFilter, 5); m_Controls.m_StartStreaming->setEnabled(false); m_Controls.m_ConnectionStatus->setText(""); m_StreamingTimer->start((1.0 / 5.0 * 1000.0)); } void QmitkUltrasoundCalibration::OnGetPlusCalibration() { m_TransformClient = mitk::IGTLClient::New(true); m_TransformClient->SetHostname("127.0.0.1"); m_TransformClient->SetPortNumber(18946); m_TransformDeviceSource = mitk::IGTLDeviceSource::New(); m_TransformDeviceSource->SetIGTLDevice(m_TransformClient); m_TransformDeviceSource->Connect(); if (m_TransformDeviceSource->IsConnected()) { MITK_INFO << "successfully connected"; m_TransformDeviceSource->StartCommunication(); if (m_TransformDeviceSource->IsCommunicating()) { MITK_INFO << "communication started"; mitk::IGTLMessage::Pointer receivedMessage; bool condition = false; igtl::Matrix4x4 transformPLUS; while (!(receivedMessage.IsNotNull() && receivedMessage->IsDataValid())) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); m_TransformDeviceSource->Update(); receivedMessage = m_TransformDeviceSource->GetOutput(); igtl::TransformMessage::Pointer msg = dynamic_cast(m_TransformDeviceSource->GetOutput()->GetMessage().GetPointer()); if (msg == nullptr || msg.IsNull()) { MITK_INFO << "Received message could not be casted to TransformMessage. Skipping.."; continue; } else { if (std::strcmp(msg->GetDeviceName(), "ImageToTracker") != 0) { MITK_INFO << "Was not Image to Tracker Transform. Skipping..."; continue; } else { msg->GetMatrix(transformPLUS); condition = true; break; } } } if (condition) { this->ProcessPlusCalibration(transformPLUS); } else { m_Controls.m_GotCalibrationLabel->setStyleSheet("QLabel { color : red; }"); m_Controls.m_GotCalibrationLabel->setText("Something went wrong. Please try again"); } } else { MITK_INFO << " no connection"; m_Controls.m_GotCalibrationLabel->setStyleSheet("QLabel { color : red; }"); m_Controls.m_GotCalibrationLabel->setText("Something went wrong. Please try again"); } } else { m_Controls.m_GotCalibrationLabel->setStyleSheet("QLabel { color : red; }"); m_Controls.m_GotCalibrationLabel->setText("Something went wrong. Please try again"); } } void QmitkUltrasoundCalibration::ProcessPlusCalibration(igtl::Matrix4x4& imageToTracker) { mitk::AffineTransform3D::Pointer imageToTrackerTransform = mitk::AffineTransform3D::New(); itk::Matrix rotationFloat = itk::Matrix(); itk::Vector translationFloat = itk::Vector(); rotationFloat[0][0] = imageToTracker[0][0]; rotationFloat[0][1] = imageToTracker[0][1]; rotationFloat[0][2] = imageToTracker[0][2]; rotationFloat[1][0] = imageToTracker[1][0]; rotationFloat[1][1] = imageToTracker[1][1]; rotationFloat[1][2] = imageToTracker[1][2]; rotationFloat[2][0] = imageToTracker[2][0]; rotationFloat[2][1] = imageToTracker[2][1]; rotationFloat[2][2] = imageToTracker[2][2]; translationFloat[0] = imageToTracker[0][3]; translationFloat[1] = imageToTracker[1][3]; translationFloat[2] = imageToTracker[2][3]; imageToTrackerTransform->SetTranslation(translationFloat); imageToTrackerTransform->SetMatrix(rotationFloat); m_CombinedModality->SetCalibration(imageToTrackerTransform); m_Controls.m_ToolBox->setItemEnabled(2, true); m_Controls.m_SavePlusCalibration->setEnabled(true); m_Controls.m_GotCalibrationLabel->setStyleSheet("QLabel { color : green; }"); m_Controls.m_GotCalibrationLabel->setText("Recieved Calibration from PLUS you can now save it"); } void QmitkUltrasoundCalibration::OnStopCalibrationProcess() { this->ClearTemporaryMembers(); m_Timer->stop(); this->GetDataStorage()->Remove(m_Node); m_Node = 0; this->GetDataStorage()->Remove(m_CalibNode); m_CalibNode = 0; this->GetDataStorage()->Remove(m_WorldNode); m_WorldNode = 0; m_Controls.m_ToolBox->setCurrentIndex(0); } void QmitkUltrasoundCalibration::OnDeciveServiceEvent(const ctkServiceEvent event) { if (m_CombinedModality.IsNull() || event.getType() != ctkServiceEvent::MODIFIED) { return; } ctkServiceReference service = event.getServiceReference(); QString curDepth = service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH)).toString(); if (m_CurrentDepth != curDepth) { m_CurrentDepth = curDepth; this->OnReset(); } } void QmitkUltrasoundCalibration::OnAddCalibPoint() { mitk::Point3D world = this->GetRenderWindowPart()->GetSelectedPosition(); this->m_CalibPointsImage->InsertPoint(m_CalibPointsCount, world); this->m_CalibPointsTool->InsertPoint(m_CalibPointsCount, this->m_FreezePoint); QString text = text.number(m_CalibPointsCount + 1); text = "Point " + text; this->m_Controls.m_CalibPointList->addItem(text); m_CalibPointsCount++; SwitchFreeze(); } void QmitkUltrasoundCalibration::OnCalibration() { // Compute transformation vtkSmartPointer transform = vtkSmartPointer::New(); transform->SetSourceLandmarks(this->ConvertPointSetToVtkPolyData(m_CalibPointsImage)->GetPoints()); transform->SetTargetLandmarks(this->ConvertPointSetToVtkPolyData(m_CalibPointsTool)->GetPoints()); if (m_Controls.m_ScaleTransform->isChecked()) { transform->SetModeToSimilarity(); } //use affine transform else { transform->SetModeToRigidBody(); } //use similarity transform: scaling is not touched transform->Modified(); transform->Update(); // Convert from vtk to itk data types itk::Matrix rotationFloat = itk::Matrix(); itk::Vector translationFloat = itk::Vector(); vtkSmartPointer m = transform->GetMatrix(); rotationFloat[0][0] = m->GetElement(0, 0); rotationFloat[0][1] = m->GetElement(0, 1); rotationFloat[0][2] = m->GetElement(0, 2); rotationFloat[1][0] = m->GetElement(1, 0); rotationFloat[1][1] = m->GetElement(1, 1); rotationFloat[1][2] = m->GetElement(1, 2); rotationFloat[2][0] = m->GetElement(2, 0); rotationFloat[2][1] = m->GetElement(2, 1); rotationFloat[2][2] = m->GetElement(2, 2); translationFloat[0] = m->GetElement(0, 3); translationFloat[1] = m->GetElement(1, 3); translationFloat[2] = m->GetElement(2, 3); mitk::DataNode::Pointer CalibPointsImage = mitk::DataNode::New(); CalibPointsImage->SetName("Calibration Points Image"); CalibPointsImage->SetData(m_CalibPointsImage); this->GetDataStorage()->Add(CalibPointsImage); mitk::DataNode::Pointer CalibPointsTracking = mitk::DataNode::New(); CalibPointsTracking->SetName("Calibration Points Tracking"); CalibPointsTracking->SetData(m_CalibPointsTool); this->GetDataStorage()->Add(CalibPointsTracking); mitk::PointSet::Pointer ImagePointsTransformed = m_CalibPointsImage->Clone(); this->ApplyTransformToPointSet(ImagePointsTransformed, transform); mitk::DataNode::Pointer CalibPointsImageTransformed = mitk::DataNode::New(); CalibPointsImageTransformed->SetName("Calibration Points Image (Transformed)"); CalibPointsImageTransformed->SetData(ImagePointsTransformed); this->GetDataStorage()->Add(CalibPointsImageTransformed); // Set output variable mitk::AffineTransform3D::Pointer oldUSImageTransform = m_Image->GetGeometry()->GetIndexToWorldTransform(); //including spacing! MITK_INFO << "Old US Image transform: " << oldUSImageTransform; mitk::AffineTransform3D::Pointer calibTransform = mitk::AffineTransform3D::New(); calibTransform->SetTranslation(translationFloat); calibTransform->SetMatrix(rotationFloat); MITK_INFO << "Calibration transform: " << calibTransform; m_Transformation = mitk::AffineTransform3D::New(); if (!m_Controls.m_ScaleTransform->isChecked()) { m_Transformation->Compose(oldUSImageTransform); } m_Transformation->Compose(calibTransform); MITK_INFO << "New combined transform: " << m_Transformation; mitk::SlicedGeometry3D::Pointer sliced3d = dynamic_cast (m_Node->GetData()->GetGeometry()); mitk::PlaneGeometry::Pointer plane = const_cast (sliced3d->GetPlaneGeometry(0)); plane->SetIndexToWorldTransform(m_Transformation); // Save to US-Device m_CombinedModality->SetCalibration(m_Transformation); m_Controls.m_ToolBox->setItemEnabled(2, true); // Save to NeedleProjectionFilter m_NeedleProjectionFilter->SetTargetPlane(m_Transformation); // Update Calibration FRE m_CalibrationStatistics = mitk::PointSetDifferenceStatisticsCalculator::New(); mitk::PointSet::Pointer p1 = this->m_CalibPointsTool->Clone(); // We use clones to calculate statistics to avoid concurrency Problems // Create point set with transformed image calibration points for // calculating the difference of image calibration and tool // calibration points in one geometry space mitk::PointSet::Pointer p2 = mitk::PointSet::New(); int n = 0; for (mitk::PointSet::PointsConstIterator it = m_CalibPointsImage->Begin(); it != m_CalibPointsImage->End(); ++it, ++n) { p2->InsertPoint(n, m_Transformation->TransformPoint(it->Value())); } m_CalibrationStatistics->SetPointSets(p1, p2); //QString text = text.number(m_CalibrationStatistics->GetRMS()); QString text = QString::number(ComputeFRE(m_CalibPointsImage, m_CalibPointsTool, transform)); MITK_INFO << "Calibration FRE: " << text.toStdString().c_str(); m_Controls.m_EvalLblCalibrationFRE->setText(text); m_Node->SetStringProperty("Calibration FRE", text.toStdString().c_str()); // Enable Button to save Calibration m_Controls.m_CalibBtnSaveCalibration->setEnabled(true); } void QmitkUltrasoundCalibration::OnAddEvalTargetPoint() { mitk::Point3D world = this->GetRenderWindowPart()->GetSelectedPosition(); this->m_EvalPointsImage->InsertPoint(m_EvalPointsImage->GetSize(), world); this->m_EvalPointsTool->InsertPoint(m_EvalPointsTool->GetSize(), this->m_FreezePoint); QString text = text.number(this->m_EvalPointsTool->GetSize()); this->m_Controls.m_EvalLblNumTargetPoints->setText(text); // Update FREs // Update Evaluation FRE, but only if it contains more than one point (will crash otherwise) if ((m_EvalPointsProjected->GetSize() > 1) && (m_EvalPointsTool->GetSize() > 1)) { m_EvaluationStatistics = mitk::PointSetDifferenceStatisticsCalculator::New(); m_ProjectionStatistics = mitk::PointSetDifferenceStatisticsCalculator::New(); mitk::PointSet::Pointer p1 = this->m_EvalPointsTool->Clone(); // We use clones to calculate statistics to avoid concurrency Problems mitk::PointSet::Pointer p2 = this->m_EvalPointsImage->Clone(); mitk::PointSet::Pointer p3 = this->m_EvalPointsProjected->Clone(); m_EvaluationStatistics->SetPointSets(p1, p2); m_ProjectionStatistics->SetPointSets(p1, p3); QString evalText = evalText.number(m_EvaluationStatistics->GetRMS()); QString projText = projText.number(m_ProjectionStatistics->GetRMS()); m_Controls.m_EvalLblEvaluationFRE->setText(evalText); m_Controls.m_EvalLblProjectionFRE->setText(projText); } SwitchFreeze(); } void QmitkUltrasoundCalibration::OnAddEvalProjectedPoint() { MITK_WARN << "Projection Evaluation may currently be inaccurate."; // TODO: Verify correct Evaluation. Is the Point that is added really current? mitk::Point3D projection = this->m_NeedleProjectionFilter->GetProjection()->GetPoint(1); m_EvalPointsProjected->InsertPoint(m_EvalPointsProjected->GetSize(), projection); QString text = text.number(this->m_EvalPointsProjected->GetSize()); this->m_Controls.m_EvalLblNumProjectionPoints->setText(text); } void QmitkUltrasoundCalibration::OnSaveEvaluation() { //Filename without suffix QString filename = m_Controls.m_EvalFilePath->text() + "//" + m_Controls.m_EvalFilePrefix->text(); MITK_WARN << "CANNOT SAVE, ABORTING!"; /* not working any more TODO! mitk::PointSetWriter::Pointer psWriter = mitk::PointSetWriter::New(); psWriter->SetInput(0, m_CalibPointsImage); psWriter->SetInput(1, m_CalibPointsTool); psWriter->SetInput(2, m_EvalPointsImage); psWriter->SetInput(3, m_EvalPointsTool); psWriter->SetInput(4, m_EvalPointsProjected); psWriter->SetFileName(filename.toStdString() + ".xml"); psWriter->Write(); */ // TODO: New writer for transformations must be implemented. /* mitk::TransformationFileWriter::Pointer tWriter = mitk::TransformationFileWriter::New(); tWriter->SetInput(0, m_CalibPointsImage); tWriter->SetInput(1, m_CalibPointsTool); tWriter->SetInput(2, m_EvalPointsImage); tWriter->SetInput(3, m_EvalPointsTool); tWriter->SetInput(4, m_EvalPointsProjected); tWriter->SetOutputFilename(filename.toStdString() + ".txt"); tWriter->DoWrite(this->m_Transformation); */ } void QmitkUltrasoundCalibration::OnSaveCalibration() { m_Controls.m_GotCalibrationLabel->setText(""); QString filename = QFileDialog::getSaveFileName(QApplication::activeWindow(), "Save Calibration", "", "Calibration files *.cal"); QFile file(filename); if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { MITK_WARN << "Cannot open file '" << filename.toStdString() << "' for writing."; return; } std::string calibrationSerialization = m_CombinedModality->SerializeCalibration(); QTextStream outStream(&file); outStream << QString::fromStdString(calibrationSerialization); //save additional information if (m_Controls.m_saveAdditionalCalibrationLog->isChecked()) { mitk::SceneIO::Pointer mySceneIO = mitk::SceneIO::New(); QString filenameScene = filename + "_mitkScene.mitk"; mitk::NodePredicateNot::Pointer isNotHelperObject = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true))); mitk::DataStorage::SetOfObjects::ConstPointer nodesToBeSaved = this->GetDataStorage()->GetSubset(isNotHelperObject); mySceneIO->SaveScene(nodesToBeSaved, this->GetDataStorage(), filenameScene.toStdString().c_str()); } } void QmitkUltrasoundCalibration::OnReset() { this->ClearTemporaryMembers(); if (m_Transformation.IsNull()) { m_Transformation = mitk::AffineTransform3D::New(); } m_Transformation->SetIdentity(); if (m_Node.IsNotNull() && (m_Node->GetData() != nullptr) && (m_Node->GetData()->GetGeometry() != nullptr)) { mitk::SlicedGeometry3D::Pointer sliced3d = dynamic_cast (m_Node->GetData()->GetGeometry()); mitk::PlaneGeometry::Pointer plane = const_cast (sliced3d->GetPlaneGeometry(0)); plane->SetIndexToWorldTransform(m_Transformation); } QString text1 = text1.number(this->m_EvalPointsTool->GetSize()); this->m_Controls.m_EvalLblNumTargetPoints->setText(text1); QString text2 = text2.number(this->m_EvalPointsProjected->GetSize()); this->m_Controls.m_EvalLblNumProjectionPoints->setText(text2); } void QmitkUltrasoundCalibration::Update() { //QList nodes = this->GetDataManagerSelection(); // if (nodes.empty()) return; // Update Tracking Data std::vector* datas = new std::vector(); datas->push_back(m_Tracker->GetOutput()); m_Controls.m_CalibTrackingStatus->SetNavigationDatas(datas); m_Controls.m_CalibTrackingStatus->Refresh(); m_Controls.m_EvalTrackingStatus->SetNavigationDatas(datas); m_Controls.m_EvalTrackingStatus->Refresh(); // Update US Image m_CombinedModality->Modified(); m_CombinedModality->Update(); mitk::Image::Pointer m_Image = m_CombinedModality->GetOutput(); if (m_Image.IsNotNull() && m_Image->IsInitialized()) { if (m_OverrideSpacing) { m_Image->GetGeometry()->SetSpacing(m_Spacing); } if (m_Image.IsNotNull() && m_Image->IsInitialized()) { m_Node->SetData(m_Image); } } + m_Node->SetData(m_Image); //Workaround because image is not initalized, maybe problem of the Ultrasound view? // Update Needle Projection m_NeedleProjectionFilter->Update(); //only update 2d window because it is faster - //this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); + this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); } void QmitkUltrasoundCalibration::SwitchFreeze() { m_Controls.m_CalibBtnAddPoint->setEnabled(false); // generally deactivate // We use the activity state of the timer to determine whether we are currently viewing images if (!m_Timer->isActive()) // Activate Imaging { // if (m_Node) m_Node->ReleaseData(); if (m_CombinedModality.IsNull()){ m_Timer->stop(); return; } m_CombinedModality->Update(); m_Image = m_CombinedModality->GetOutput(); if (m_Image.IsNotNull() && m_Image->IsInitialized()) { m_Node->SetData(m_Image); } std::vector datas; datas.push_back(m_Tracker->GetOutput()); m_Controls.m_CalibTrackingStatus->SetNavigationDatas(&datas); m_Controls.m_CalibTrackingStatus->ShowStatusLabels(); m_Controls.m_CalibTrackingStatus->Refresh(); m_Controls.m_EvalTrackingStatus->SetNavigationDatas(&datas); m_Controls.m_EvalTrackingStatus->ShowStatusLabels(); m_Controls.m_EvalTrackingStatus->Refresh(); int interval = 40; m_Timer->setInterval(interval); m_Timer->start(); - m_CombinedModality->SetIsFreezed(false); + m_CombinedModality->GetUltrasoundDevice()->SetIsFreezed(false); } else if (this->m_Tracker->GetOutput(0)->IsDataValid()) { //deactivate Imaging m_Timer->stop(); // Remember last tracking coordinates m_FreezePoint = this->m_Tracker->GetOutput(0)->GetPosition(); m_Controls.m_CalibBtnAddPoint->setEnabled(true); // activate only, if valid point is set - m_CombinedModality->SetIsFreezed(true); + m_CombinedModality->GetUltrasoundDevice()->SetIsFreezed(true); } } void QmitkUltrasoundCalibration::ShowNeedlePath() { // Init Filter this->m_NeedleProjectionFilter->SelectInput(0); // Create Node for Pointset mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode("Needle Path"); if (node.IsNull()) { node = mitk::DataNode::New(); node->SetName("Needle Path"); node->SetData(m_NeedleProjectionFilter->GetProjection()); node->SetBoolProperty("show contour", true); this->GetDataStorage()->Add(node); } } void QmitkUltrasoundCalibration::ClearTemporaryMembers() { m_CalibPointsTool->Clear(); m_CalibPointsImage->Clear(); m_CalibPointsCount = 0; m_EvalPointsImage->Clear(); m_EvalPointsTool->Clear(); m_EvalPointsProjected->Clear(); this->m_Controls.m_CalibPointList->clear(); m_SpacingPoints->Clear(); m_Controls.m_SpacingPointsList->clear(); m_SpacingPointsCount = 0; } vtkSmartPointer QmitkUltrasoundCalibration::ConvertPointSetToVtkPolyData(mitk::PointSet::Pointer PointSet) { vtkSmartPointer returnValue = vtkSmartPointer::New(); vtkSmartPointer points = vtkSmartPointer::New(); for (int i = 0; i < PointSet->GetSize(); i++) { double point[3] = { PointSet->GetPoint(i)[0], PointSet->GetPoint(i)[1], PointSet->GetPoint(i)[2] }; points->InsertNextPoint(point); } vtkSmartPointer temp = vtkSmartPointer::New(); temp->SetPoints(points); vtkSmartPointer vertexFilter = vtkSmartPointer::New(); vertexFilter->SetInputData(temp); vertexFilter->Update(); returnValue->ShallowCopy(vertexFilter->GetOutput()); return returnValue; } double QmitkUltrasoundCalibration::ComputeFRE(mitk::PointSet::Pointer imageFiducials, mitk::PointSet::Pointer realWorldFiducials, vtkSmartPointer transform) { if (imageFiducials->GetSize() != realWorldFiducials->GetSize()) return -1; double FRE = 0; for (int i = 0; i < imageFiducials->GetSize(); ++i) { itk::Point current_image_fiducial_point = imageFiducials->GetPoint(i); if (transform != nullptr) { current_image_fiducial_point = transform->TransformPoint(imageFiducials->GetPoint(i)[0], imageFiducials->GetPoint(i)[1], imageFiducials->GetPoint(i)[2]); } double cur_error_squared = current_image_fiducial_point.SquaredEuclideanDistanceTo(realWorldFiducials->GetPoint(i)); FRE += cur_error_squared; } FRE = sqrt(FRE / (double)imageFiducials->GetSize()); return FRE; } void QmitkUltrasoundCalibration::ApplyTransformToPointSet(mitk::PointSet::Pointer pointSet, vtkSmartPointer transform) { for (int i = 0; i < pointSet->GetSize(); ++i) { itk::Point current_point_transformed = itk::Point(); current_point_transformed = transform->TransformPoint(pointSet->GetPoint(i)[0], pointSet->GetPoint(i)[1], pointSet->GetPoint(i)[2]); pointSet->SetPoint(i, current_point_transformed); } } void QmitkUltrasoundCalibration::OnFreezeClicked() { - if (m_CombinedModality->GetIsFreezed()) + if (m_CombinedModality->GetUltrasoundDevice()->GetIsFreezed()) { //device was already frozen so we need to delete all Spacing points because they need to be collected all at once // no need to check if all four points are already collected, because if thats the case you can no longer click the Freeze Button m_SpacingPoints->Clear(); m_Controls.m_SpacingPointsList->clear(); m_SpacingPointsCount = 0; m_Controls.m_SpacingAddPoint->setEnabled(false); - m_CombinedModality->SetIsFreezed(false); + m_CombinedModality->GetUltrasoundDevice()->SetIsFreezed(false); } else { - m_CombinedModality->SetIsFreezed(true); + m_CombinedModality->GetUltrasoundDevice()->SetIsFreezed(true); m_Controls.m_SpacingAddPoint->setEnabled(true); } //SwitchFreeze(); } void QmitkUltrasoundCalibration::OnAddSpacingPoint() { mitk::Point3D point = this->GetRenderWindowPart()->GetSelectedPosition(); this->m_SpacingPoints->InsertPoint(m_SpacingPointsCount, point); QString text = text.number(m_SpacingPointsCount + 1); text = "Point " + text; this->m_Controls.m_SpacingPointsList->addItem(text); m_SpacingPointsCount++; if (m_SpacingPointsCount == 4) //now we have all 4 points needed { m_Controls.m_SpacingAddPoint->setEnabled(false); m_Controls.m_CalculateSpacing->setEnabled(true); m_Controls.m_SpacingBtnFreeze->setEnabled(false); } } void QmitkUltrasoundCalibration::OnCalculateSpacing() { mitk::Point3D horizontalOne = m_SpacingPoints->GetPoint(0); mitk::Point3D horizontalTwo = m_SpacingPoints->GetPoint(1); mitk::Point3D verticalOne = m_SpacingPoints->GetPoint(2); mitk::Point3D verticalTwo = m_SpacingPoints->GetPoint(3); //Get the distances between the points in the image double xDistance = horizontalOne.EuclideanDistanceTo(horizontalTwo); double yDistance = verticalOne.EuclideanDistanceTo(verticalTwo); //Calculate the spacing of the image and fill a vector with it double xSpacing = 30 / xDistance; double ySpacing = 20 / yDistance; m_Spacing[0] = xSpacing; m_Spacing[1] = ySpacing; m_Spacing[2] = 1; MITK_INFO << m_Spacing; //Make sure the new spacing is applied to the USVideoDeviceImages m_OverrideSpacing = true; //Now that the spacing is set clear all stuff and return to Calibration m_SpacingPoints->Clear(); m_Controls.m_SpacingPointsList->clear(); m_SpacingPointsCount = 0; - m_CombinedModality->SetIsFreezed(false); + m_CombinedModality->GetUltrasoundDevice()->SetIsFreezed(false); } void QmitkUltrasoundCalibration::OnUSDepthChanged(const std::string& key, const std::string&) { //whenever depth of USImage is changed the spacing should no longer be overwritten if (key == mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH) { m_OverrideSpacing = false; } } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUltrasoundCalibration.h b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUltrasoundCalibration.h index 7efae7c8ab..a073d54c19 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUltrasoundCalibration.h +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUltrasoundCalibration.h @@ -1,348 +1,348 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkUltrasoundCalibration_h #define QmitkUltrasoundCalibration_h #include #include //QT //#include //MITK #include #include #include #include #include #include // Microservices #include "ui_QmitkUltrasoundCalibrationControls.h" #include #include #include #include /*! \brief QmitkUltrasoundCalibration \warning This view provides a simple calibration process. \sa QmitkFunctionality \ingroup ${plugin_target}_internal */ class QmitkUltrasoundCalibration : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: QmitkUltrasoundCalibration(); ~QmitkUltrasoundCalibration(); static const std::string VIEW_ID; virtual void CreateQtPartControl(QWidget *parent); void OnUSDepthChanged(const std::string&, const std::string&); protected slots: /** * \brief Triggered, whenever the user switches Tabs * */ void OnTabSwitch(int index); /** * \brief Triggered, when the user has clicked "select Devices". * */ //void OnSelectDevice(mitk::USCombinedModality::Pointer); void OnDeviceSelected(); void OnDeviceDeselected(); /** * \brief Triggered, when the user clicks "Add Point" * */ void OnAddCalibPoint(); /** * \brief Triggered, when the user clicks "Calibrate" * */ void OnCalibration(); /** * \brief Triggered, when the user clicks "Add Target Points". * * Adds an image point and an tracking point to their respective evaluation pointsets */ void OnAddEvalTargetPoint(); /** * \brief Triggered, when the user clicks "Add Point". * * Adds a projected point to the projected point evaluation set. */ void OnAddEvalProjectedPoint(); /** * \brief Triggered when the user clicks "Save Results" in the Evaluation tab. */ void OnSaveEvaluation(); /** * \brief Triggered when the user clicks "Save Calibration" in the Calibration tab. */ void OnSaveCalibration(); /** * \brief Triggered when the user clicks "Run Next Round". Also used as a reset mechanism. */ void OnReset(); /** * \brief Triggered in regular intervals by a timer, when live view is enabled. * */ void Update(); /** * \brief Freezes or unfreezes the image. */ void SwitchFreeze(); /** * */ void OnStartCalibrationProcess(); /** *\brief Method to use the PLUS-Toolkoit for Calibration of EchoTrack */ void OnStartPlusCalibration(); void OnStopPlusCalibration(); /** *\ brief Starts the Streaming of USImage and Navigation Data when PLUS is connected */ void OnStartStreaming(); void OnNewConnection(); /** \*brief Get the Calibration from the PLUS-Toolkit once Calibration with fCal is done */ void OnGetPlusCalibration(); /** \*brief Convert the recieved igtl::Matrix into an mitk::AffineTransform3D which can be used to calibrate the CombinedModality */ void ProcessPlusCalibration(igtl::Matrix4x4& imageToTracker); void OnStreamingTimerTimeout(); /** * */ void OnStopCalibrationProcess(); void OnAddCurrentTipPositionToReferencePoints(); void OnStartVerification(); void OnAddCurrentTipPositionForVerification(); void OnDeciveServiceEvent(const ctkServiceEvent event); void OnFreezeClicked(); void OnAddSpacingPoint(); void OnCalculateSpacing(); signals: /** * \brief used for thread seperation, the worker thread must not call OnNewConnection directly. * QT signals are thread safe and separate the threads */ void NewConnectionSignal(); protected: virtual void SetFocus(); /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer source, const QList& nodes); Ui::QmitkUltrasoundCalibrationControls m_Controls; /** * \brief Internal function that activates display of the needle path. */ void ShowNeedlePath(); /** * \brief Clears all member attributes which are holding intermediate results for the calibration. */ void ClearTemporaryMembers(); void OnPlusConnected(); /** * \brief The combined modality used for imaging and tracking. */ - mitk::USCombinedModality::Pointer m_CombinedModality; + mitk::AbstractUltrasoundTrackerDevice::Pointer m_CombinedModality; /** * \brief NavigationDataSource used for tracking data. * This will be gotten by the combined modality. */ mitk::NavigationDataSource::Pointer m_Tracker; QTimer *m_Timer; mitk::DataNode::Pointer m_Node; mitk::DataNode::Pointer m_CalibNode; mitk::DataNode::Pointer m_WorldNode; //IGTL Servers and Devices needed for the communication with PLUS mitk::IGTLServer::Pointer m_USServer; mitk::IGTLMessageProvider::Pointer m_USMessageProvider; mitk::ImageToIGTLMessageFilter::Pointer m_USImageToIGTLMessageFilter; mitk::IGTLServer::Pointer m_TrackingServer; mitk::IGTLMessageProvider::Pointer m_TrackingMessageProvider; mitk::NavigationDataToIGTLMessageFilter::Pointer m_TrackingToIGTLMessageFilter; mitk::IGTLClient::Pointer m_TransformClient; mitk::IGTLDeviceSource::Pointer m_TransformDeviceSource; QTimer *m_StreamingTimer; unsigned long m_NewConnectionObserverTag; // Variables to determine if spacing was calibrated and needs to be applied to the incoming images mitk::Vector3D m_Spacing; bool m_OverrideSpacing; /** * \brief The current Ultrasound Image. */ mitk::Image::Pointer m_Image; /** * \brief Current point when the image was last frozen. */ mitk::Point3D m_FreezePoint; /** * \brief Pointset containing all tool points. */ mitk::PointSet::Pointer m_CalibPointsImage; /** * \brief Pointset containing corresponding points on the image. */ mitk::PointSet::Pointer m_CalibPointsTool; /** * \brief Pointset containing Projected Points (aka "where we thought the needle was gonna land") */ mitk::PointSet::Pointer m_EvalPointsProjected; /** * \brief Pointset containing the evaluated points on the image. */ mitk::PointSet::Pointer m_EvalPointsImage; /** * \brief Pointset containing tracked evaluation points. */ mitk::PointSet::Pointer m_EvalPointsTool; /** * \brief Pointset containing tracked evaluation points. */ mitk::PointSet::Pointer m_VerificationReferencePoints; mitk::DataNode::Pointer m_VerificationReferencePointsDataNode; int m_currentPoint; std::vector m_allReferencePoints; std::vector m_allErrors; /** * \brief Pointset containing points along the needle's prohected path. Only used for visualization. The first point is the needle tip. */ //mitk::PointSet::Pointer m_NeedlePathPoints; /** * \brief Creates a Pointset that projects the needle's path */ mitk::NeedleProjectionFilter::Pointer m_NeedleProjectionFilter; /** * \brief Total number of calibration points set. */ int m_CalibPointsCount; QString m_CurrentDepth; /** * \brief StatisticsRegarding Projection Accuracy. * (Compares m_EvalPointsProjected to m_EvalPointsImage) */ mitk::PointSetDifferenceStatisticsCalculator::Pointer m_ProjectionStatistics; /** * \brief StatisticsRegarding Evaluation Accuracy. * (Compares m_EvalPointsTool to m_EvalPointsImage) */ mitk::PointSetDifferenceStatisticsCalculator::Pointer m_EvaluationStatistics; /** * \brief StatisticsRegarding Calibration Accuracy. * (Compares m_CalibPointsTool to a transformed copy of m_CalibPointsImage). */ mitk::PointSetDifferenceStatisticsCalculator::Pointer m_CalibrationStatistics; /** * \brief Result of the Calibration. */ mitk::AffineTransform3D::Pointer m_Transformation; /** * This method is copied from PointSetModifier which is part of MBI. It should be replaced * by external method call as soon as this functionality will be available in MITK. */ vtkSmartPointer ConvertPointSetToVtkPolyData(mitk::PointSet::Pointer PointSet); double ComputeFRE(mitk::PointSet::Pointer imageFiducials, mitk::PointSet::Pointer realWorldFiducials, vtkSmartPointer transform = nullptr); void ApplyTransformToPointSet(mitk::PointSet::Pointer pointSet, vtkSmartPointer transform); mitk::PointSet::Pointer m_SpacingPoints; mitk::DataNode::Pointer m_SpacingNode; int m_SpacingPointsCount; private: mitk::MessageDelegate2 m_USDeviceChanged; }; #endif // UltrasoundCalibration_h diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/SettingsWidgets/QmitkUSNavigationCombinedSettingsWidget.h b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/SettingsWidgets/QmitkUSNavigationCombinedSettingsWidget.h index 4b18edce98..0150da4b10 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/SettingsWidgets/QmitkUSNavigationCombinedSettingsWidget.h +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/SettingsWidgets/QmitkUSNavigationCombinedSettingsWidget.h @@ -1,53 +1,53 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKUSNAVIGATIONCOMBINEDSETTINGSWIDGET_H #define QMITKUSNAVIGATIONCOMBINEDSETTINGSWIDGET_H #include "QmitkUSNavigationAbstractSettingsWidget.h" #include "mitkDataNode.h" namespace Ui { class QmitkUSNavigationCombinedSettingsWidget; } /** * \brief Settings widget for the USNavigationMarkerPlacement. * This widgets allows for configuring the experiment mode and for changing the * application between marker placement and punctuation. */ class QmitkUSNavigationCombinedSettingsWidget : public QmitkUSNavigationAbstractSettingsWidget { Q_OBJECT protected slots: void OnApplicationChanged(int); public: explicit QmitkUSNavigationCombinedSettingsWidget(QWidget *parent = 0); ~QmitkUSNavigationCombinedSettingsWidget(); + virtual void OnSetSettingsNode(itk::SmartPointer settingsNode, bool overwriteValues); protected: - virtual void OnSetSettingsNode(itk::SmartPointer settingsNode, bool overwriteValues); virtual void OnSaveProcessing(); virtual void OnLoadSettingsProcessing(); QString InteractionNameToFile(const QString& name) const; private: Ui::QmitkUSNavigationCombinedSettingsWidget *ui; }; #endif // QMITKUSNAVIGATIONCOMBINEDSETTINGSWIDGET_H diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityCreationWidget.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityCreationWidget.cpp index 62955187e3..19b7efb0f3 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityCreationWidget.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityCreationWidget.cpp @@ -1,81 +1,81 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkUSCombinedModalityCreationWidget.h" #include "ui_QmitkUSCombinedModalityCreationWidget.h" QmitkUSCombinedModalityCreationWidget::QmitkUSCombinedModalityCreationWidget(QWidget *parent) : QWidget(parent), ui(new Ui::QmitkUSCombinedModalityCreationWidget) { ui->setupUi(this); std::string filterExcludeCombinedModalities = "(&(" + us::ServiceConstants::OBJECTCLASS() + "=" + "org.mitk.services.UltrasoundDevice)(!(" + mitk::USDevice::GetPropertyKeys().US_PROPKEY_CLASS + "=" + mitk::USCombinedModality::DeviceClassIdentifier + ")))"; connect(ui->usDevicesServiceList, SIGNAL(ServiceSelectionChanged(us::ServiceReferenceU)), this, SLOT(OnSelectedUltrasoundOrTrackingDevice())); connect(ui->trackingDevicesServiceList, SIGNAL(ServiceSelectionChanged(us::ServiceReferenceU)), this, SLOT(OnSelectedUltrasoundOrTrackingDevice())); ui->usDevicesServiceList->SetAutomaticallySelectFirstEntry(true); ui->trackingDevicesServiceList->SetAutomaticallySelectFirstEntry(true); ui->usDevicesServiceList->Initialize(mitk::USDevice::GetPropertyKeys().US_PROPKEY_LABEL, filterExcludeCombinedModalities); ui->trackingDevicesServiceList->Initialize(mitk::NavigationDataSource::US_PROPKEY_DEVICENAME); connect(ui->createButton, SIGNAL(clicked()), this, SLOT(OnCreation())); connect(ui->cancelButton, SIGNAL(clicked()), this, SIGNAL(SignalAborted())); } QmitkUSCombinedModalityCreationWidget::~QmitkUSCombinedModalityCreationWidget() { delete ui; } void QmitkUSCombinedModalityCreationWidget::OnCreation() { mitk::USDevice::Pointer usDevice = ui->usDevicesServiceList->GetSelectedService(); if (usDevice.IsNull()) { MITK_WARN << "No Ultrasound Device selected for creation of Combined Modality."; return; } mitk::NavigationDataSource::Pointer trackingDevice = ui->trackingDevicesServiceList->GetSelectedService(); if (trackingDevice.IsNull()) { MITK_WARN << "No Traccking Device selected for creation of Combined Modality."; return; } QString vendor = ui->vendorLineEdit->text(); QString name = ui->nameLineEdit->text(); if (name.isEmpty()) { name = "Combined Modality"; } - mitk::USCombinedModality::Pointer combinedModality = mitk::USCombinedModality::New( - usDevice, trackingDevice, vendor.toStdString(), name.toStdString()); - combinedModality->Initialize(); - combinedModality->RegisterAsMicroservice(); // register as micro service + m_CombinedModality = mitk::USCombinedModality::New(usDevice, trackingDevice, false); + + m_CombinedModality->GetUltrasoundDevice()->Initialize(); + m_CombinedModality->RegisterAsMicroservice(); // register as micro service emit SignalCreated(); - emit SignalCreated(combinedModality); + //emit SignalCreated(m_CombinedModality); } void QmitkUSCombinedModalityCreationWidget::OnSelectedUltrasoundOrTrackingDevice() { // create button is enabled only if an ultrasound // and a tracking device is selected ui->createButton->setEnabled( ui->usDevicesServiceList->GetIsServiceSelected() && ui->trackingDevicesServiceList->GetIsServiceSelected()); } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityCreationWidget.h b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityCreationWidget.h index f98b4f8e65..1b43d5ea25 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityCreationWidget.h +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityCreationWidget.h @@ -1,62 +1,64 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKUSCOMBINEDMODALITYCREATIONWIDGET_H #define QMITKUSCOMBINEDMODALITYCREATIONWIDGET_H #include #include "mitkUSCombinedModality.h" namespace Ui { class QmitkUSCombinedModalityCreationWidget; } /** * \brief Widget that enables the user to create a mitk::USCombinedModality of a mitk::NavigationDataSource and a mitk::USDevice. * A mitk::NavigationDataSource and a mitk::USDevice can be picked from two lists, showing * the corresponding micro service objects. The combined modality is registered as a micro * service as well during the creation process. */ class QmitkUSCombinedModalityCreationWidget : public QWidget { Q_OBJECT signals: /** \brief Emmited when the user clicks the "Cancel" button. */ void SignalAborted(); /** \brief Emmited when the user clicked the "Create" button and the creation is successfull. */ void SignalCreated(mitk::USCombinedModality::Pointer combinedModality); /** \brief Emmited when the user clicked the "Create" button and the creation is successfull. */ void SignalCreated(); protected slots: /** \brief Creates a combined modility of the selected mitk::NavigationDataSource and mitk::USDevice. **/ void OnCreation(); /** \brief Handles the enabled state of the "Create" button. **/ void OnSelectedUltrasoundOrTrackingDevice(); public: explicit QmitkUSCombinedModalityCreationWidget(QWidget *parent = 0); ~QmitkUSCombinedModalityCreationWidget(); private: Ui::QmitkUSCombinedModalityCreationWidget *ui; + + itk::SmartPointer m_CombinedModality; }; #endif // QMITKUSCOMBINEDMODALITYCREATIONWIDGET_H diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityEditWidget.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityEditWidget.cpp index 7386a037de..87531c2631 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityEditWidget.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityEditWidget.cpp @@ -1,159 +1,159 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkUSCombinedModalityEditWidget.h" #include "ui_QmitkUSCombinedModalityEditWidget.h" #include "mitkUSControlInterfaceBMode.h" #include "mitkUSControlInterfaceProbes.h" #include "../QmitkUSNavigationCalibrationsDataModel.h" #include "../QmitkUSNavigationCalibrationRemoveDelegate.h" #include "../QmitkUSNavigationCalibrationUpdateDepthDelegate.h" #include #include #include QmitkUSCombinedModalityEditWidget::QmitkUSCombinedModalityEditWidget(QWidget *parent) : QWidget(parent), m_CalibrationsDataModel(new QmitkUSNavigationCalibrationsDataModel(this)), m_CalibrationUpdateDepthDelegate(new QmitkUSNavigationCalibrationUpdateDepthDelegate(this)), ui(new Ui::QmitkUSCombinedModalityEditWidget) { ui->setupUi(this); ui->calibrationsTable->setModel(m_CalibrationsDataModel); ui->calibrationsTable->setItemDelegateForColumn(2, new QmitkUSNavigationCalibrationRemoveDelegate(this)); ui->calibrationsTable->setItemDelegateForColumn(0, m_CalibrationUpdateDepthDelegate); } QmitkUSCombinedModalityEditWidget::~QmitkUSCombinedModalityEditWidget() { delete ui; } -void QmitkUSCombinedModalityEditWidget::SetCombinedModality(mitk::USCombinedModality::Pointer combinedModality) +void QmitkUSCombinedModalityEditWidget::SetCombinedModality(mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality) { m_CalibrationsDataModel->SetCombinedModality(combinedModality); m_CombinedModality = combinedModality; if ( combinedModality.IsNull() ) { return; } m_LastCalibrations = m_CombinedModality->SerializeCalibration(); - ui->vendorLineEdit->setText(QString::fromStdString(combinedModality->GetManufacturer())); - ui->nameLineEdit->setText(QString::fromStdString(combinedModality->GetName())); + ui->vendorLineEdit->setText(QString::fromStdString(combinedModality->GetUltrasoundDevice()->GetManufacturer())); + ui->nameLineEdit->setText(QString::fromStdString(combinedModality->GetUltrasoundDevice()->GetName())); ui->ultrasoundDeviceLabel->setText(QString::fromStdString(combinedModality->GetUltrasoundDevice()->GetManufacturer() + " " + combinedModality->GetUltrasoundDevice()->GetName())); ui->trackingDeviceLabel->setText(QString::fromStdString(combinedModality->GetNavigationDataSource()->GetName())); mitk::USDevice::Pointer usDevice = combinedModality->GetUltrasoundDevice(); if ( usDevice.IsNull() ) { return; } mitk::USControlInterfaceBMode::Pointer controlInterfaceBMode = usDevice->GetControlInterfaceBMode(); if ( controlInterfaceBMode.IsNull() ) { return; } m_CalibrationUpdateDepthDelegate->SetControlInterfaceBMode(controlInterfaceBMode); } void QmitkUSCombinedModalityEditWidget::OnSaveButtonClicked() { if ( m_CombinedModality.IsNotNull() ) { - m_CombinedModality->SetManufacturer(ui->vendorLineEdit->text().toStdString()); - m_CombinedModality->SetName(ui->nameLineEdit->text().toStdString()); + m_CombinedModality->GetUltrasoundDevice()->SetManufacturer(ui->vendorLineEdit->text().toStdString()); + m_CombinedModality->GetUltrasoundDevice()->SetName(ui->nameLineEdit->text().toStdString()); m_LastCalibrations = m_CombinedModality->SerializeCalibration(); } emit SignalSaved(); } void QmitkUSCombinedModalityEditWidget::OnCancelButtonClicked() { if ( m_CombinedModality.IsNotNull() && ! m_LastCalibrations.empty() ) { // restore previous calibrations if cancel button was clicked m_CombinedModality->DeserializeCalibration(m_LastCalibrations); } emit SignalAborted(); } void QmitkUSCombinedModalityEditWidget::OnCalibrationsSaveButtonClicked() { if ( m_CombinedModality.IsNull() ) { MITK_WARN << "Cannot save calibrations as no combined modality is available."; return; } QString filename = QFileDialog::getSaveFileName( QApplication::activeWindow(), "Save Calibrations", "", "Calibration files *.cal" ); QFile file(filename); if ( ! file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate) ) { MITK_WARN << "Cannot open file '" << filename.toStdString() << "' for writing."; return; } std::string calibrationSerialization = m_CombinedModality->SerializeCalibration(); QTextStream outStream(&file); outStream << QString::fromStdString(calibrationSerialization); } void QmitkUSCombinedModalityEditWidget::OnCalibrationsLoadButtonClicked() { if ( m_CombinedModality.IsNull() ) { MITK_WARN << "Cannot load calibrations as no combined modality is available."; return; } QString filename = QFileDialog::getOpenFileName( QApplication::activeWindow(), "Load Calibration", "", "Calibration files *.cal" ); if ( filename.isNull() ) { return; } QFile file(filename); if ( ! file.open(QIODevice::ReadOnly | QIODevice::Text) ) { MITK_WARN << "Cannot open file '" << filename.toStdString() << "' for reading."; return; } QTextStream inStream(&file); std::string calibration = inStream.readAll().toStdString(); if ( calibration.empty() ) { MITK_WARN << "Failed to load file. Unsupported format?"; return; } try { m_CombinedModality->DeserializeCalibration(calibration, false); } catch ( const mitk::Exception& /*exception*/ ) { MITK_WARN << "Failed to deserialize calibration. Unsuppoerted format?"; return; } // make sure that the table model is up to date m_CalibrationsDataModel->SetCombinedModality(m_CombinedModality); } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityEditWidget.h b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityEditWidget.h index 0a97cf70b1..e1a822a14b 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityEditWidget.h +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityEditWidget.h @@ -1,61 +1,61 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKUSCOMBINEDMODALITYEDITWIDGET_H #define QMITKUSCOMBINEDMODALITYEDITWIDGET_H #include #include "mitkUSCombinedModality.h" namespace Ui { class QmitkUSCombinedModalityEditWidget; } class QmitkUSNavigationCalibrationsDataModel; class QmitkUSNavigationCalibrationUpdateDepthDelegate; class QmitkUSCombinedModalityEditWidget : public QWidget { Q_OBJECT signals: void SignalSaved(); void SignalAborted(); protected slots: void OnSaveButtonClicked(); void OnCancelButtonClicked(); void OnCalibrationsSaveButtonClicked(); void OnCalibrationsLoadButtonClicked(); public: explicit QmitkUSCombinedModalityEditWidget(QWidget *parent = 0); ~QmitkUSCombinedModalityEditWidget(); - void SetCombinedModality(mitk::USCombinedModality::Pointer combinedModality); + void SetCombinedModality(mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality); private: - mitk::USCombinedModality::Pointer m_CombinedModality; + mitk::AbstractUltrasoundTrackerDevice::Pointer m_CombinedModality; std::string m_LastCalibrations; QmitkUSNavigationCalibrationsDataModel* m_CalibrationsDataModel; QmitkUSNavigationCalibrationUpdateDepthDelegate* m_CalibrationUpdateDepthDelegate; Ui::QmitkUSCombinedModalityEditWidget* ui; }; #endif // QMITKUSCOMBINEDMODALITYEDITWIDGET_H diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationFreezeButton.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationFreezeButton.cpp index 9017f35302..fdf97175d2 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationFreezeButton.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationFreezeButton.cpp @@ -1,136 +1,136 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkUSNavigationFreezeButton.h" #include QmitkUSNavigationFreezeButton::QmitkUSNavigationFreezeButton(QWidget* parent) : QPushButton(parent), m_OutputIndex(-1), m_FreezeButtonToggle(true) { this->setText("Freeze Imaging"); this->setIcon(QIcon(":/USNavigation/system-lock-screen.png")); this->setCheckable(true); //set shortcuts QShortcut *shortcut = new QShortcut(QKeySequence("F12"), parent); connect(shortcut, SIGNAL(activated()), this, SLOT(OnFreezeButtonToggle())); connect(this, SIGNAL(clicked(bool)), this, SLOT(OnButtonClicked(bool))); } QmitkUSNavigationFreezeButton::~QmitkUSNavigationFreezeButton() { } -void QmitkUSNavigationFreezeButton::SetCombinedModality(mitk::USCombinedModality::Pointer combinedModality, int outputIndex) +void QmitkUSNavigationFreezeButton::SetCombinedModality(mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality, int outputIndex) { m_CombinedModality = combinedModality; m_OutputIndex = outputIndex; } void QmitkUSNavigationFreezeButton::Freeze() { if ( ! this->isChecked() ) { this->setChecked(true); this->OnButtonClicked(true); } } void QmitkUSNavigationFreezeButton::Unfreeze() { if ( this->isChecked() ) { this->setChecked(false); this->OnButtonClicked(false); } } void QmitkUSNavigationFreezeButton::OnFreezeButtonToggle() { if(this->isVisible()) { this->setChecked(m_FreezeButtonToggle); OnButtonClicked(m_FreezeButtonToggle); } } void QmitkUSNavigationFreezeButton::OnButtonClicked(bool checked) { // cannot do anything without a combined modality if ( m_CombinedModality.IsNull() ) { MITK_WARN("QmitkUSNavigationFreezeButton") << "Cannot freeze the device as the device is null."; this->setChecked(false); m_FreezeButtonToggle = true; return; } m_FreezeButtonToggle = !checked; // cannot do anything without a navigation data source mitk::NavigationDataSource::Pointer navigationDataSource = m_CombinedModality->GetNavigationDataSource(); if ( navigationDataSource.IsNull() ) { MITK_WARN("QmitkUSNavigationFreezeButton") << "Cannot freeze the device as the NavigationDataSource is null."; this->setChecked(false); return; } if (checked) //freezing { MITK_INFO << "Freezing"; // freeze the imaging and the tracking - m_CombinedModality->SetIsFreezed(true); + m_CombinedModality->GetUltrasoundDevice()->SetIsFreezed(true); if ( m_OutputIndex >= 0 ) { // make sure that the navigation data is up to date navigationDataSource->Update(); // unfreeze if the navigation data got invalid during the time between // the button click and the actual freeze if ( checked && ! navigationDataSource->GetOutput(m_OutputIndex)->IsDataValid() ) { MITK_WARN("QmitkUSNavigationStepZoneMarking")("QmitkUSNavigationStepTumourSelection") << "Unfreezing device as the last tracking data of the reference sensor wasn't valid."; - m_CombinedModality->SetIsFreezed(false); + m_CombinedModality->GetUltrasoundDevice()->SetIsFreezed(false); this->setChecked(false); return; } } emit SignalFreezed(true); } else //unfreezing { MITK_INFO << "Unfreezing"; emit SignalFreezed(false); //m_CombinedModality->SetIsFreezed(false);//commented out to workaround bug: may only be unfreezed after critical structure was added } } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationFreezeButton.h b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationFreezeButton.h index f55d7a7c2a..6fe9e97ac0 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationFreezeButton.h +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationFreezeButton.h @@ -1,81 +1,81 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKUSNAVIGATIONFREEZEBUTTON_H #define QMITKUSNAVIGATIONFREEZEBUTTON_H #include #include "mitkUSCombinedModality.h" /** * \brief QPushButton for freezing and unfreezing a combined modality. * The button already has an icon and a text. On every successfull * freeze or unfreeze the signal SignalFrezzed() is emitted. One should * listen to this signal rather than to the clicked() signal of the * QPushButton as the combined modality may not be freezed after * clicked() was emitted. */ class QmitkUSNavigationFreezeButton : public QPushButton { Q_OBJECT signals: /** * \brief Emitted every time the freeze state of the combined modality changed. * True if the combined modality is freezed now, false if it isn't. */ void SignalFreezed(bool); protected slots: void OnButtonClicked(bool checked); void OnFreezeButtonToggle(); public: explicit QmitkUSNavigationFreezeButton(QWidget* parent = 0); ~QmitkUSNavigationFreezeButton(); /** * \brief Setter for the combined modality to be freezed by this button. * An index may be specified for a tracking data output. The combined * modality will only be freezed then, if the current tracking data of * this output is valid. */ - void SetCombinedModality(mitk::USCombinedModality::Pointer combinedModality, int outputIndex = -1); + void SetCombinedModality(mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality, int outputIndex = -1); /** * \brief Try to freeze the combined modality. * This does the same as clicking the button while the combined * modality isn't freezed. If the combined modality is already * freezed this method does nothing. */ void Freeze(); /** * \brief Unfreeze the combined modality. * This does the same as clicking the button while the combined * modality is freezed. If the combined modality isn't freezed * this method does nothing. */ void Unfreeze(); private: - mitk::USCombinedModality::Pointer m_CombinedModality; + mitk::AbstractUltrasoundTrackerDevice::Pointer m_CombinedModality; int m_OutputIndex; bool m_FreezeButtonToggle; }; #endif // QMITKUSNAVIGATIONFREEZEBUTTON_H diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationProcessWidget.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationProcessWidget.cpp index 0ef68154c7..e38511fa7e 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationProcessWidget.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationProcessWidget.cpp @@ -1,557 +1,564 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkUSNavigationProcessWidget.h" #include "ui_QmitkUSNavigationProcessWidget.h" #include "../NavigationStepWidgets/QmitkUSAbstractNavigationStep.h" #include "../SettingsWidgets/QmitkUSNavigationAbstractSettingsWidget.h" #include "mitkDataNode.h" #include "mitkNavigationDataToNavigationDataFilter.h" #include #include #include QmitkUSNavigationProcessWidget::QmitkUSNavigationProcessWidget(QWidget* parent) : QWidget(parent), m_SettingsWidget(0), m_BaseNode(mitk::DataNode::New()), m_CurrentTabIndex(0), m_CurrentMaxStep(0), m_ImageAlreadySetToNode(false), m_ReadySignalMapper(new QSignalMapper(this)), m_NoLongerReadySignalMapper(new QSignalMapper(this)), m_StdMultiWidget(0), m_UsePlanningStepWidget(false), ui(new Ui::QmitkUSNavigationProcessWidget) { m_Parent = parent; ui->setupUi(this); // remove the default page ui->stepsToolBox->setCurrentIndex(1);// ->removeItem(0); //set shortcuts QShortcut *nextShortcut = new QShortcut(QKeySequence("F10"), parent); QShortcut *prevShortcut = new QShortcut(QKeySequence("F11"), parent); connect(nextShortcut, SIGNAL(activated()), this, SLOT(OnNextButtonClicked())); connect(prevShortcut, SIGNAL(activated()), this, SLOT(OnPreviousButtonClicked())); //connect other slots connect( ui->restartStepButton, SIGNAL(clicked()), this, SLOT(OnRestartStepButtonClicked()) ); connect( ui->previousButton, SIGNAL(clicked()), this, SLOT(OnPreviousButtonClicked()) ); connect( ui->nextButton, SIGNAL(clicked()), this, SLOT(OnNextButtonClicked()) ); connect( ui->stepsToolBox, SIGNAL(currentChanged(int)), this, SLOT(OnTabChanged(int)) ); connect (ui->settingsButton, SIGNAL(clicked()), this, SLOT(OnSettingsButtonClicked()) ); connect( m_ReadySignalMapper, SIGNAL(mapped(int)), this, SLOT(OnStepReady(int)) ); connect( m_NoLongerReadySignalMapper, SIGNAL(mapped(int)), this, SLOT(OnStepNoLongerReady(int)) ); ui->settingsFrameWidget->setHidden(true); } +itk::SmartPointer QmitkUSNavigationProcessWidget::GetSettingsNode() +{ + return m_SettingsNode; +} + QmitkUSNavigationProcessWidget::~QmitkUSNavigationProcessWidget() { ui->stepsToolBox->blockSignals(true); for ( NavigationStepVector::iterator it = m_NavigationSteps.begin(); it != m_NavigationSteps.end(); ++it ) { if ( (*it)->GetNavigationStepState() > QmitkUSAbstractNavigationStep::State_Stopped ) { (*it)->StopStep(); } delete *it; } m_NavigationSteps.clear(); if ( m_SettingsNode.IsNotNull() && m_DataStorage.IsNotNull() ) { m_DataStorage->Remove(m_SettingsNode); } delete ui; } void QmitkUSNavigationProcessWidget::EnableInteraction(bool enable) { if (enable) { ui->restartStepButton->setEnabled(true); ui->previousButton->setEnabled(true); ui->nextButton->setEnabled(true); ui->stepsToolBox->setEnabled(true); } else { ui->restartStepButton->setEnabled(false); ui->previousButton->setEnabled(false); ui->nextButton->setEnabled(false); ui->stepsToolBox->setEnabled(false); } } void QmitkUSNavigationProcessWidget::SetDataStorage(itk::SmartPointer dataStorage) { m_DataStorage = dataStorage; if ( dataStorage.IsNull() ) { mitkThrow() << "Data Storage must not be null for QmitkUSNavigationProcessWidget."; } // test if base node is already in the data storage and add it if not m_BaseNode = dataStorage->GetNamedNode(QmitkUSAbstractNavigationStep::DATANAME_BASENODE); if ( m_BaseNode.IsNull() ) { m_BaseNode = mitk::DataNode::New(); m_BaseNode->SetName(QmitkUSAbstractNavigationStep::DATANAME_BASENODE); dataStorage->Add(m_BaseNode); } // base node and image stream node may be the same node if ( strcmp(QmitkUSAbstractNavigationStep::DATANAME_BASENODE, QmitkUSAbstractNavigationStep::DATANAME_IMAGESTREAM) != 0) { m_ImageStreamNode = dataStorage->GetNamedNode(QmitkUSAbstractNavigationStep::DATANAME_IMAGESTREAM); if (m_ImageStreamNode.IsNull()) { // Create Node for US Stream m_ImageStreamNode = mitk::DataNode::New(); m_ImageStreamNode->SetName(QmitkUSAbstractNavigationStep::DATANAME_IMAGESTREAM); dataStorage->Add(m_ImageStreamNode); } } else { m_ImageStreamNode = m_BaseNode; } m_SettingsNode = dataStorage->GetNamedDerivedNode(QmitkUSAbstractNavigationStep::DATANAME_SETTINGS, m_BaseNode); if ( m_SettingsNode.IsNull() ) { m_SettingsNode = mitk::DataNode::New(); m_SettingsNode->SetName(QmitkUSAbstractNavigationStep::DATANAME_SETTINGS); dataStorage->Add(m_SettingsNode, m_BaseNode); } if (m_SettingsWidget) { m_SettingsWidget->SetSettingsNode(m_SettingsNode); } } void QmitkUSNavigationProcessWidget::SetSettingsWidget(QmitkUSNavigationAbstractSettingsWidget* settingsWidget) { // disconnect slots to settings widget if there was a widget before if ( m_SettingsWidget ) { disconnect( ui->settingsSaveButton, SIGNAL(clicked()), m_SettingsWidget, SLOT(OnSave()) ); disconnect( ui->settingsCancelButton, SIGNAL(clicked()), m_SettingsWidget, SLOT(OnCancel()) ); disconnect (m_SettingsWidget, SIGNAL(Saved()), this, SLOT(OnSettingsWidgetReturned()) ); disconnect (m_SettingsWidget, SIGNAL(Canceled()), this, SLOT(OnSettingsWidgetReturned()) ); disconnect (m_SettingsWidget, SIGNAL(SettingsChanged(itk::SmartPointer)), this, SLOT(OnSettingsChanged(itk::SmartPointer)) ); ui->settingsWidget->removeWidget(m_SettingsWidget); } m_SettingsWidget = settingsWidget; if ( m_SettingsWidget ) { m_SettingsWidget->LoadSettings(); connect( ui->settingsSaveButton, SIGNAL(clicked()), m_SettingsWidget, SLOT(OnSave()) ); connect( ui->settingsCancelButton, SIGNAL(clicked()), m_SettingsWidget, SLOT(OnCancel()) ); connect (m_SettingsWidget, SIGNAL(Saved()), this, SLOT(OnSettingsWidgetReturned()) ); connect (m_SettingsWidget, SIGNAL(Canceled()), this, SLOT(OnSettingsWidgetReturned()) ); connect (m_SettingsWidget, SIGNAL(SettingsChanged(itk::SmartPointer)), this, SLOT(OnSettingsChanged(itk::SmartPointer)) ); if ( m_SettingsNode.IsNotNull() ) { m_SettingsWidget->SetSettingsNode(m_SettingsNode, true); } ui->settingsWidget->addWidget(m_SettingsWidget); } ui->settingsButton->setEnabled(m_SettingsWidget != 0); } void QmitkUSNavigationProcessWidget::SetNavigationSteps(NavigationStepVector navigationSteps) { disconnect( this, SLOT(OnTabChanged(int)) ); for ( int n = ui->stepsToolBox->count()-1; n >= 0; --n ) { //ui->stepsToolBox->removeItem(n); } connect( ui->stepsToolBox, SIGNAL(currentChanged(int)), this, SLOT(OnTabChanged(int)) ); m_NavigationSteps.clear(); m_NavigationSteps = navigationSteps; this->InitializeNavigationStepWidgets(); // notify all navigation step widgets about the current settings for (NavigationStepIterator it = m_NavigationSteps.begin(); it != m_NavigationSteps.end(); ++it) { (*it)->OnSettingsChanged(m_SettingsNode); } } void QmitkUSNavigationProcessWidget::ResetNavigationProcess() { MITK_INFO("QmitkUSNavigationProcessWidget") << "Resetting navigation process."; ui->stepsToolBox->blockSignals(true); for ( int n = 0; n <= m_CurrentMaxStep; ++n ) { m_NavigationSteps.at(n)->StopStep(); //if ( n > 0 ) { ui->stepsToolBox->setItemEnabled(n, false); } } ui->stepsToolBox->blockSignals(false); m_CurrentMaxStep = 0; ui->stepsToolBox->setCurrentIndex(0); if ( m_NavigationSteps.size() > 0 ) { m_NavigationSteps.at(0)->ActivateStep(); } this->UpdatePrevNextButtons(); } void QmitkUSNavigationProcessWidget::UpdateNavigationProgress() { - if ( m_CombinedModality.IsNotNull() && !m_CombinedModality->GetIsFreezed() ) + if ( m_CombinedModality.IsNotNull() && !m_CombinedModality->GetUltrasoundDevice()->GetIsFreezed() ) { m_CombinedModality->Modified(); m_CombinedModality->Update(); if ( m_LastNavigationDataFilter.IsNotNull() ) { m_LastNavigationDataFilter->Update(); } mitk::Image::Pointer image = m_CombinedModality->GetOutput(); // make sure that always the current image is set to the data node if ( image.IsNotNull() && m_ImageStreamNode->GetData() != image.GetPointer() && image->IsInitialized() ) { m_ImageStreamNode->SetData(image); m_ImageAlreadySetToNode = true; } } if ( m_CurrentTabIndex > 0 && static_cast(m_CurrentTabIndex) < m_NavigationSteps.size() ) { m_NavigationSteps.at(m_CurrentTabIndex)->Update(); } } void QmitkUSNavigationProcessWidget::OnNextButtonClicked() { - if (m_CombinedModality.IsNotNull() && m_CombinedModality->GetIsFreezed()) {return;} //no moving through steps when the modality is nullptr or frozen + emit SignalNextButtonClicked(); + if (m_CombinedModality.IsNotNull() && m_CombinedModality->GetUltrasoundDevice()->GetIsFreezed()) {return;} //no moving through steps when the modality is nullptr or frozen int currentIndex = ui->stepsToolBox->currentIndex(); if (currentIndex >= m_CurrentMaxStep) { MITK_WARN << "Next button clicked though no next tab widget is available."; return; } ui->stepsToolBox->setCurrentIndex(++currentIndex); this->UpdatePrevNextButtons(); + } void QmitkUSNavigationProcessWidget::OnPreviousButtonClicked() { - if (m_CombinedModality.IsNotNull() && m_CombinedModality->GetIsFreezed()) {return;} //no moving through steps when the modality is nullptr or frozen + if (m_CombinedModality.IsNotNull() && m_CombinedModality->GetUltrasoundDevice()->GetIsFreezed()) {return;} //no moving through steps when the modality is nullptr or frozen int currentIndex = ui->stepsToolBox->currentIndex(); if (currentIndex <= 0) { MITK_WARN << "Previous button clicked though no previous tab widget is available."; return; } ui->stepsToolBox->setCurrentIndex(--currentIndex); this->UpdatePrevNextButtons(); } void QmitkUSNavigationProcessWidget::OnRestartStepButtonClicked() { MITK_DEBUG("QmitkUSNavigationProcessWidget") << "Restarting step " << m_CurrentTabIndex << " (" << m_NavigationSteps.at(m_CurrentTabIndex)->GetTitle().toStdString() << ")."; m_NavigationSteps.at(ui->stepsToolBox->currentIndex())->RestartStep(); m_NavigationSteps.at(ui->stepsToolBox->currentIndex())->ActivateStep(); } void QmitkUSNavigationProcessWidget::OnTabChanged(int index) { emit SignalActiveNavigationStepChangeRequested(index); if ( index < 0 || index >= static_cast(m_NavigationSteps.size()) ) { return; } else if ( m_CurrentTabIndex == index ) { // just activate the step if it is the same step againg m_NavigationSteps.at(index)->ActivateStep(); return; } MITK_DEBUG("QmitkUSNavigationProcessWidget") << "Activating navigation step " << index << " (" << m_NavigationSteps.at(index)->GetTitle().toStdString() <<")."; if (index > m_CurrentTabIndex) { this->UpdateFilterPipeline(); // finish all previous steps to make sure that all data is valid for (int n = m_CurrentTabIndex; n < index; ++n) { m_NavigationSteps.at(n)->FinishStep(); } } // deactivate the previously active step if ( m_CurrentTabIndex > 0 && m_NavigationSteps.size() > static_cast(m_CurrentTabIndex) ) { m_NavigationSteps.at(m_CurrentTabIndex)->DeactivateStep(); } // start step of the current tab if it wasn't started before if ( m_NavigationSteps.at(index)->GetNavigationStepState() == QmitkUSAbstractNavigationStep::State_Stopped ) { m_NavigationSteps.at(index)->StartStep(); } m_NavigationSteps.at(index)->ActivateStep(); if (static_cast(index) < m_NavigationSteps.size()) ui->restartStepButton->setEnabled(m_NavigationSteps.at(index)->GetIsRestartable()); this->UpdatePrevNextButtons(); m_CurrentTabIndex = index; emit SignalActiveNavigationStepChanged(index); } void QmitkUSNavigationProcessWidget::OnSettingsButtonClicked() { this->SetSettingsWidgetVisible(true); } void QmitkUSNavigationProcessWidget::OnSettingsWidgetReturned() { this->SetSettingsWidgetVisible(false); } void QmitkUSNavigationProcessWidget::OnSettingsNodeChanged(itk::SmartPointer dataNode) { if ( m_SettingsWidget ) m_SettingsWidget->SetSettingsNode(dataNode); } void QmitkUSNavigationProcessWidget::OnStepReady(int index) { if (m_CurrentMaxStep <= index) { m_CurrentMaxStep = index + 1; this->UpdatePrevNextButtons(); for (int n = 0; n <= m_CurrentMaxStep; ++n) { //ui->stepsToolBox->setItemEnabled(n, true); } } emit SignalNavigationStepFinished(index, true); } void QmitkUSNavigationProcessWidget::OnStepNoLongerReady(int index) { if (m_CurrentMaxStep > index) { m_CurrentMaxStep = index; this->UpdatePrevNextButtons(); this->UpdateFilterPipeline(); for (int n = m_CurrentMaxStep+1; n < ui->stepsToolBox->count(); ++n) { //ui->stepsToolBox->setItemEnabled(n, false); m_NavigationSteps.at(n)->StopStep(); } } emit SignalNavigationStepFinished(index, false); } -void QmitkUSNavigationProcessWidget::OnCombinedModalityChanged(itk::SmartPointer combinedModality) +void QmitkUSNavigationProcessWidget::OnCombinedModalityChanged(itk::SmartPointer combinedModality) { m_CombinedModality = combinedModality; m_ImageAlreadySetToNode = false; if ( combinedModality.IsNotNull() ) { if ( combinedModality->GetNavigationDataSource().IsNull() ) { MITK_WARN << "There is no navigation data source set for the given combined modality."; return; } this->UpdateFilterPipeline(); } for (NavigationStepIterator it = m_NavigationSteps.begin(); it != m_NavigationSteps.end(); ++it) { (*it)->SetCombinedModality(combinedModality); } emit SignalCombinedModalityChanged(combinedModality); } void QmitkUSNavigationProcessWidget::OnSettingsChanged(const mitk::DataNode::Pointer dataNode) { static bool methodEntered = false; if ( methodEntered ) { MITK_WARN("QmitkUSNavigationProcessWidget") << "Ignoring recursive call to 'OnSettingsChanged()'. " << "Make sure to no emit 'SignalSettingsNodeChanged' in an 'OnSettingsChanged()' method."; return; } methodEntered = true; std::string application; if ( dataNode->GetStringProperty("settings.application", application) ) { QString applicationQString = QString::fromStdString(application); if ( applicationQString != ui->titleLabel->text() ) { ui->titleLabel->setText(applicationQString); } } // notify all navigation step widgets about the changed settings for (NavigationStepIterator it = m_NavigationSteps.begin(); it != m_NavigationSteps.end(); ++it) { (*it)->OnSettingsChanged(dataNode); } emit SignalSettingsChanged(dataNode); methodEntered = false; } void QmitkUSNavigationProcessWidget::InitializeNavigationStepWidgets() { // do not listen for steps tool box signal during insertion of items into tool box disconnect( ui->stepsToolBox, SIGNAL(currentChanged(int)), this, SLOT(OnTabChanged(int)) ); m_CurrentMaxStep = 0; mitk::DataStorage::Pointer dataStorage = m_DataStorage; for (unsigned int n = 0; n < m_NavigationSteps.size(); ++n) { QmitkUSAbstractNavigationStep* curNavigationStep = m_NavigationSteps.at(n); curNavigationStep->SetDataStorage(dataStorage); connect( curNavigationStep, SIGNAL(SignalReadyForNextStep()), m_ReadySignalMapper, SLOT(map())); connect( curNavigationStep, SIGNAL(SignalNoLongerReadyForNextStep()), m_NoLongerReadySignalMapper, SLOT(map()) ); connect( curNavigationStep, SIGNAL(SignalCombinedModalityChanged(itk::SmartPointer)), this, SLOT(OnCombinedModalityChanged(itk::SmartPointer)) ); connect( curNavigationStep, SIGNAL(SignalIntermediateResult(const itk::SmartPointer)), this, SIGNAL(SignalIntermediateResult(const itk::SmartPointer)) ); connect( curNavigationStep, SIGNAL(SignalSettingsNodeChanged(itk::SmartPointer)), this, SLOT(OnSettingsNodeChanged(itk::SmartPointer)) ); m_ReadySignalMapper->setMapping(curNavigationStep, n); m_NoLongerReadySignalMapper->setMapping(curNavigationStep, n); ui->stepsToolBox->insertWidget(n, curNavigationStep); //if ( n > 0 ) { ui->stepsToolBox->get(n, false); } } ui->restartStepButton->setEnabled(m_NavigationSteps.at(0)->GetIsRestartable()); ui->stepsToolBox->setCurrentIndex(0); // activate the first navigation step widgets if ( ! m_NavigationSteps.empty() ) { m_NavigationSteps.at(0)->ActivateStep(); } // after filling the steps tool box the signal is interesting again connect( ui->stepsToolBox, SIGNAL(currentChanged(int)), this, SLOT(OnTabChanged(int)) ); this->UpdateFilterPipeline(); } void QmitkUSNavigationProcessWidget::UpdatePrevNextButtons() { int currentIndex = ui->stepsToolBox->currentIndex(); ui->previousButton->setEnabled(currentIndex > 0); ui->nextButton->setEnabled(currentIndex < m_CurrentMaxStep); } void QmitkUSNavigationProcessWidget::UpdateFilterPipeline() { if ( m_CombinedModality.IsNull() ) { return; } std::vector filterList; mitk::NavigationDataSource::Pointer navigationDataSource = m_CombinedModality->GetNavigationDataSource(); for (unsigned int n = 0; n <= static_cast(m_CurrentMaxStep) && n < m_NavigationSteps.size(); ++n) { QmitkUSAbstractNavigationStep::FilterVector filter = m_NavigationSteps.at(n)->GetFilter(); if ( ! filter.empty() ) { filterList.insert(filterList.end(), filter.begin(), filter.end()); } } if ( ! filterList.empty() ) { for (unsigned int n = 0; n < navigationDataSource->GetNumberOfOutputs(); ++n) { filterList.at(0)->SetInput(n, navigationDataSource->GetOutput(n)); } for (std::vector::iterator it = filterList.begin()+1; it != filterList.end(); ++it) { std::vector::iterator prevIt = it-1; for (unsigned int n = 0; n < (*prevIt)->GetNumberOfOutputs(); ++n) { (*it)->SetInput(n, (*prevIt)->GetOutput(n)); } } m_LastNavigationDataFilter = filterList.at(filterList.size()-1); } else { m_LastNavigationDataFilter = navigationDataSource.GetPointer(); } } void QmitkUSNavigationProcessWidget::SetSettingsWidgetVisible(bool visible) { ui->settingsFrameWidget->setVisible(visible); ui->stepsToolBox->setHidden(visible); ui->settingsButton->setHidden(visible); ui->restartStepButton->setHidden(visible); ui->previousButton->setHidden(visible); ui->nextButton->setHidden(visible); } void QmitkUSNavigationProcessWidget::FinishCurrentNavigationStep() { int currentIndex = ui->stepsToolBox->currentIndex(); QmitkUSAbstractNavigationStep* curNavigationStep = m_NavigationSteps.at(currentIndex); curNavigationStep->FinishStep(); } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationProcessWidget.h b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationProcessWidget.h index 1a78fd3998..8c33a14002 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationProcessWidget.h +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationProcessWidget.h @@ -1,179 +1,183 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef USNAVIGATIONPROCESSWIDGET_H #define USNAVIGATIONPROCESSWIDGET_H #include #include #include #include namespace itk { template class SmartPointer; } namespace mitk { class NodeDisplacementFilter; } namespace Ui { class QmitkUSNavigationProcessWidget; } class QmitkUSAbstractNavigationStep; class QmitkUSNavigationAbstractSettingsWidget; class QmitkUSNavigationStepCombinedModality; class QmitkStdMultiWidget; class QTimer; class QSignalMapper; /** * \brief Widget for handling navigation steps. * The navigation steps (subclasses of QmitkUSAbstractNavigationStep) can be set * in a vector. The coordination of this steps is done by this widget then. */ class QmitkUSNavigationProcessWidget : public QWidget { Q_OBJECT signals: /** * \brief Signals a replacement of the combined modality by one of the navigation steps. */ - void SignalCombinedModalityChanged(itk::SmartPointer); + void SignalCombinedModalityChanged(itk::SmartPointer); /** * \brief Signals a change of the navigation settings. */ void SignalSettingsChanged(itk::SmartPointer); /** * \brief Signals if a change of the currently active navigation step is requested. Gives the index of the new step. */ void SignalActiveNavigationStepChangeRequested(int); /** * \brief Signals a change of the currently active navigation step after the step was changed. */ void SignalActiveNavigationStepChanged(int); /** * \brief Signals that the navigation step with the given id was finished. */ void SignalNavigationStepFinished(int, bool); + void SignalNextButtonClicked(); + /** * \brief Signals the creation of an intermediate result. * The result data is given as properties of the data node. */ void SignalIntermediateResult(const itk::SmartPointer); protected slots: void OnNextButtonClicked(); void OnPreviousButtonClicked(); void OnRestartStepButtonClicked(); void OnTabChanged(int index); void OnSettingsButtonClicked(); void OnSettingsWidgetReturned(); void OnSettingsNodeChanged(itk::SmartPointer); void OnStepReady(int); void OnStepNoLongerReady(int); - void OnCombinedModalityChanged(itk::SmartPointer); + void OnCombinedModalityChanged(itk::SmartPointer); void OnSettingsChanged(const itk::SmartPointer); public: typedef std::vector NavigationStepVector; typedef NavigationStepVector::iterator NavigationStepIterator; explicit QmitkUSNavigationProcessWidget(QWidget* parent = 0); ~QmitkUSNavigationProcessWidget(); + itk::SmartPointer GetSettingsNode(); + /** * \brief Setter for the data storage used for storing the navigation progress. */ void SetDataStorage(itk::SmartPointer dataStorage); void SetSettingsWidget(QmitkUSNavigationAbstractSettingsWidget*); /** * \brief Setter for a vector of navigation step widgets. * These widgets are used for the navigation process in the order of their * appearance in this vector. */ void SetNavigationSteps(NavigationStepVector navigationSteps); /** * \brief Forget the current progress of the navigation process. * The process will then start again at the beginning. */ void ResetNavigationProcess(); /** Enables/disables the (navigation step) interaction with this widget. * The settings button is not affected by this flag. */ void EnableInteraction(bool enable); /** Finishes the current navigation step. */ void FinishCurrentNavigationStep(); /** Updates the navigation process widget, which includes updating the * navigation pipeline. Has to be called from outside this class with * a given update rate. So no additional internal timer is needed. */ void UpdateNavigationProgress(); protected: void InitializeNavigationStepWidgets(); void UpdatePrevNextButtons(); void UpdateFilterPipeline(); void SetSettingsWidgetVisible(bool visible); itk::SmartPointer m_DataStorage; NavigationStepVector m_NavigationSteps; QmitkUSNavigationAbstractSettingsWidget* m_SettingsWidget; itk::SmartPointer m_BaseNode; itk::SmartPointer m_SettingsNode; int m_CurrentTabIndex; int m_CurrentMaxStep; itk::SmartPointer m_ImageStreamNode; bool m_ImageAlreadySetToNode; - itk::SmartPointer m_CombinedModality; + itk::SmartPointer m_CombinedModality; itk::SmartPointer m_LastNavigationDataFilter; QWidget* m_Parent; QSignalMapper* m_ReadySignalMapper; QSignalMapper* m_NoLongerReadySignalMapper; QmitkStdMultiWidget* m_StdMultiWidget; bool m_UsePlanningStepWidget; private: Ui::QmitkUSNavigationProcessWidget *ui; }; #endif // USNAVIGATIONPROCESSWIDGET_H