diff --git a/Modules/IGT/Algorithms/mitkNavigationDataDisplacementFilter.cpp b/Modules/IGT/Algorithms/mitkNavigationDataDisplacementFilter.cpp index 335c1fd11f..2d5b96caa7 100644 --- a/Modules/IGT/Algorithms/mitkNavigationDataDisplacementFilter.cpp +++ b/Modules/IGT/Algorithms/mitkNavigationDataDisplacementFilter.cpp @@ -1,73 +1,138 @@ /*=================================================================== 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 "mitkNavigationDataDisplacementFilter.h" #include "mitkPropertyList.h" #include "mitkProperties.h" mitk::NavigationDataDisplacementFilter::NavigationDataDisplacementFilter() -: mitk::NavigationDataToNavigationDataFilter() +: mitk::NavigationDataToNavigationDataFilter(), m_Transform6DOF(false) { m_Offset[0] = 0.0; m_Offset[1] = 0.0; m_Offset[2] = 0.0; + + m_Transformation = mitk::NavigationData::New(); + } mitk::NavigationDataDisplacementFilter::~NavigationDataDisplacementFilter() { } void mitk::NavigationDataDisplacementFilter::GenerateData() { /* update outputs with tracking data from tools */ - for (unsigned int i = 0; i < this->GetNumberOfOutputs() ; ++i) + if( !m_Transform6DOF ) + { + for (unsigned int i = 0; i < this->GetNumberOfOutputs() ; ++i) + { + mitk::NavigationData* output = this->GetOutput(i); + assert(output); + const mitk::NavigationData* input = this->GetInput(i); + assert(input); + + if (input->IsDataValid() == false) + { + output->SetDataValid(false); + continue; + } + output->Graft(input); // First, copy all information from input to output + output->SetPosition(input->GetPosition() + m_Offset); // Then change the member(s): add offset to position of navigation data + output->SetDataValid(true); // operation was successful, therefore data of output is valid. + // don't change anything else here + } + } + else { - mitk::NavigationData* output = this->GetOutput(i); - assert(output); - const mitk::NavigationData* input = this->GetInput(i); - assert(input); + if( this->GetNumberOfOutputs() < 2 ) + { + MITK_WARN << "TrackedUltrasound not possible. The number of tracked devices must be at least 2."; + return; + } + + //important: First device = Needle | Second device = US-Tracker + + mitk::NavigationData::Pointer needleOut = this->GetOutput(0); + const mitk::NavigationData* needleIn = this->GetInput(0); + + mitk::NavigationData::Pointer usTrackerOut = this->GetOutput(1); + const mitk::NavigationData* usTrackerIn = this->GetInput(1); - if (input->IsDataValid() == false) + if(needleIn->IsDataValid() == false ) { - output->SetDataValid(false); - continue; + needleOut->SetDataValid(false); + } + else + needleOut->Graft(needleIn); + + if (usTrackerIn->IsDataValid() == false) + { + usTrackerOut->SetDataValid(false); + } + else + usTrackerOut->Graft(usTrackerIn); + + needleOut->Compose( usTrackerOut->GetInverse(), false ); + needleOut->Compose( m_Transformation->GetInverse() ); + + usTrackerOut->SetDataValid(true); + needleOut->SetDataValid(true); + + if( this->GetNumberOfOutputs() > 2 ) + { + for( unsigned int i = 2; i < this->GetNumberOfOutputs(); ++i ) + { + mitk::NavigationData* output = this->GetOutput(i); + const mitk::NavigationData* input = this->GetInput(i); + + if (input->IsDataValid() == false) + { + output->SetDataValid(false); + continue; + } + output->Graft(input); + output->SetDataValid(true); + } } - output->Graft(input); // First, copy all information from input to output - output->SetPosition(input->GetPosition() + m_Offset); // Then change the member(s): add offset to position of navigation data - output->SetDataValid(true); // operation was successful, therefore data of output is valid. - // don't change anything else here } } +void mitk::NavigationDataDisplacementFilter::SetTransformation(mitk::AffineTransform3D::Pointer transform) +{ + mitk::NavigationData::Pointer transformation = mitk::NavigationData::New(transform); + m_Transformation = transformation; +} + void mitk::NavigationDataDisplacementFilter::SetParameters( const mitk::PropertyList* p ) { if (p == nullptr) return; mitk::Vector3D v; if (p->GetPropertyValue("NavigationDataDisplacementFilter_Offset", v) == true) // search for Offset parameter this->SetOffset(v); // apply if found; } mitk::PropertyList::ConstPointer mitk::NavigationDataDisplacementFilter::GetParameters() const { mitk::PropertyList::Pointer p = mitk::PropertyList::New(); p->SetProperty("NavigationDataDisplacementFilter_Offset", mitk::Vector3DProperty::New(this->GetOffset())); // store Offset parameter return mitk::PropertyList::ConstPointer(p); } diff --git a/Modules/IGT/Algorithms/mitkNavigationDataDisplacementFilter.h b/Modules/IGT/Algorithms/mitkNavigationDataDisplacementFilter.h index e5dfba4422..d1ae1695a4 100644 --- a/Modules/IGT/Algorithms/mitkNavigationDataDisplacementFilter.h +++ b/Modules/IGT/Algorithms/mitkNavigationDataDisplacementFilter.h @@ -1,76 +1,85 @@ /*=================================================================== 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 MITKNavigationDataDisplacementFilter_H_HEADER_INCLUDED_ #define MITKNavigationDataDisplacementFilter_H_HEADER_INCLUDED_ #include namespace mitk { /**Documentation * \brief NavigationDataDisplacementFilter adds an offset to navigation data objects * * Example class that shows how to write a navigation filter. This filter * adds a offset that can be specified as a parameter to each input navigation data. * * \ingroup IGT */ class MITKIGT_EXPORT NavigationDataDisplacementFilter : public NavigationDataToNavigationDataFilter { public: mitkClassMacro(NavigationDataDisplacementFilter, NavigationDataToNavigationDataFilter); itkFactorylessNewMacro(Self) itkCloneMacro(Self) mitkSetVectorMacro(Offset, mitk::Vector3D); ///< Get Offset parameter mitkGetVectorMacro(Offset, mitk::Vector3D); ///< Set Offset parameter + itkSetMacro(Transform6DOF, bool); + itkGetMacro(Transform6DOF, bool); + + void SetTransformation( mitk::AffineTransform3D::Pointer transform ); /** *\brief Set all filter parameters (Offset) as the PropertyList p * * This method reads the following properties from the PropertyList (name : data type): * - "NavigationDataDisplacementFilter_Offset" : mitk::Vector3DProperty */ void SetParameters(const mitk::PropertyList* p) override; /** *\brief Get all filter parameters (offset) as a PropertyList * * This method returns a PropertyList containing the following * properties (name : data type): * - "NavigationDataDisplacementFilter_Offset" : mitk::Vector3DProperty * The returned PropertyList must be assigned to a * SmartPointer immediately, or else it will get destroyed. */ mitk::PropertyList::ConstPointer GetParameters() const override; protected: NavigationDataDisplacementFilter(); ~NavigationDataDisplacementFilter() override; /**Documentation * \brief filter execute method * * adds the offset m_Offset to all inputs */ void GenerateData() override; mitk::Vector3D m_Offset; ///< offset that is added to all inputs + + bool m_Transform6DOF; + + mitk::NavigationData::Pointer m_Transformation; + }; } // namespace mitk #endif /* MITKNAVIGATIONDATATONAVIGATIONDATAFILTER_H_HEADER_INCLUDED_ */ diff --git a/Modules/US/USModel/mitkUSDevice.cpp b/Modules/US/USModel/mitkUSDevice.cpp index 05ea8dcffc..40913afa64 100644 --- a/Modules/US/USModel/mitkUSDevice.cpp +++ b/Modules/US/USModel/mitkUSDevice.cpp @@ -1,712 +1,717 @@ /*=================================================================== 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; } +unsigned int mitk::USDevice::GetSizeOfImageVector() +{ + return m_ImageVector.size(); +} + mitk::USDevice::USDevice(std::string manufacturer, std::string model) : mitk::ImageSource(), m_FreezeBarrier(nullptr), m_FreezeMutex(), m_MultiThreader(itk::MultiThreader::New()), m_ImageMutex(itk::FastMutexLock::New()), m_ThreadID(-1), m_ImageVector(), m_Spacing(), m_IGTLServer(nullptr), m_IGTLMessageProvider(nullptr), m_ImageToIGTLMsgFilter(nullptr), m_IsFreezed(false), m_DeviceState(State_NoState), m_NumberOfOutputs(1), m_ServiceProperties(), m_ServiceRegistration(), m_Manufacturer(manufacturer), m_Name(model), m_Comment(), m_SpawnAcquireThread(true), 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(m_NumberOfOutputs); // 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_FreezeBarrier(nullptr), m_FreezeMutex(), m_MultiThreader(itk::MultiThreader::New()), m_ImageMutex(itk::FastMutexLock::New()), m_ThreadID(-1), m_ImageVector(), m_Spacing(), m_IGTLServer(nullptr), m_IGTLMessageProvider(nullptr), m_ImageToIGTLMsgFilter(nullptr), m_IsFreezed(false), m_DeviceState(State_NoState), m_NumberOfOutputs(1), m_ServiceProperties(), m_ServiceRegistration(), m_SpawnAcquireThread(true), 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(m_NumberOfOutputs); // 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 nullptr; } mitk::USControlInterfaceBMode::Pointer mitk::USDevice::GetControlInterfaceBMode() { MITK_INFO << "Control interface BMode does not exist for this object."; return nullptr; } mitk::USControlInterfaceProbes::Pointer mitk::USDevice::GetControlInterfaceProbes() { MITK_INFO << "Control interface Probes does not exist for this object."; return nullptr; } mitk::USControlInterfaceDoppler::Pointer mitk::USDevice::GetControlInterfaceDoppler() { MITK_INFO << "Control interface Doppler does not exist for this object."; return nullptr; } 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() { std::vector image = this->GetUSImageSource()->GetNextImage(); m_ImageMutex->Lock(); this->SetImageVector(image); m_ImageMutex->Unlock(); } //########### 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::SetSpacing(double xSpacing, double ySpacing) { m_Spacing[0] = xSpacing; m_Spacing[1] = ySpacing; m_Spacing[2] = 1; if( m_ImageVector.size() > 0 ) { for( size_t index = 0; index < m_ImageVector.size(); ++index ) { auto& image = m_ImageVector[index]; if( image.IsNotNull() && image->IsInitialized() ) { image->GetGeometry()->SetSpacing(m_Spacing); } } this->Modified(); } MITK_INFO << "Spacing: " << m_Spacing; } void mitk::USDevice::GenerateData() { m_ImageMutex->Lock(); for (unsigned int i = 0; i < m_ImageVector.size() && i < this->GetNumberOfIndexedOutputs(); ++i) { auto& image = m_ImageVector[i]; if (image.IsNull() || !image->IsInitialized()) { // skip image } else { mitk::Image::Pointer output = this->GetOutput(i); if (!output->IsInitialized() || output->GetDimension(0) != image->GetDimension(0) || output->GetDimension(1) != image->GetDimension(1) || output->GetDimension(2) != image->GetDimension(2) || output->GetPixelType() != image->GetPixelType()) { output->Initialize(image->GetPixelType(), image->GetDimension(), image->GetDimensions()); } // copy contents of the given image into the member variable mitk::ImageReadAccessor inputReadAccessor(image); output->SetImportVolume(inputReadAccessor.GetData()); output->SetGeometry(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 095f3fbf1b..384dff6100 100644 --- a/Modules/US/USModel/mitkUSDevice.h +++ b/Modules/US/USModel/mitkUSDevice.h @@ -1,489 +1,499 @@ /*=================================================================== 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 size of the m_ImageVector of the ultrasound device.*/ unsigned int GetSizeOfImageVector(); /** @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(); virtual void SetSpacing(double xSpacing, double ySpacing); - protected: // 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 virtual void SetImageVector(std::vector vec) { if (this->m_ImageVector != vec) { this->m_ImageVector = vec; this->Modified(); } } static ITK_THREAD_RETURN_TYPE Acquire(void* pInfoStruct); static ITK_THREAD_RETURN_TYPE ConnectThread(void* pInfoStruct); std::vector m_ImageVector; // Variables to determine if spacing was calibrated and needs to be applied to the incoming images mitk::Vector3D m_Spacing; /** * \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); ~USDevice() override; /** * \brief Grabs the next frame from the Video input. * This method is called internally, whenever Update() is invoked by an Output. */ void GenerateData() override; std::string GetServicePropertyLabel(); unsigned int m_NumberOfOutputs; /** * \brief Properties of the device's Microservice. */ us::ServiceProperties m_ServiceProperties; /** * \brief The device's ServiceRegistration object that allows to modify it's Microservice registraton details. */ us::ServiceRegistration m_ServiceRegistration; 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; + + 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/USModel/mitkUSVideoDevice.h b/Modules/US/USModel/mitkUSVideoDevice.h index df205dd6c0..a1c7cc379d 100644 --- a/Modules/US/USModel/mitkUSVideoDevice.h +++ b/Modules/US/USModel/mitkUSVideoDevice.h @@ -1,252 +1,258 @@ /*=================================================================== 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 MITKUSVideoDevice_H_HEADER_INCLUDED_ #define MITKUSVideoDevice_H_HEADER_INCLUDED_ #include #include #include "mitkUSDevice.h" #include "mitkUSImageVideoSource.h" #include "mitkUSProbe.h" #include namespace itk { template class SmartPointer; } namespace mitk { class USVideoDeviceCustomControls; class USAbstractControlInterface; /** * \brief A mitk::USVideoDevice is the common class for video only devices. * They capture video input either from a file or from a device and * transform the output into an mitk::USImage with attached metadata. * This simple implementation does only capture and display 2d images without * registration for example. * * \ingroup US */ class MITKUS_EXPORT USVideoDevice : public mitk::USDevice { public: mitkClassMacro(USVideoDevice, mitk::USDevice); // To open a device (DeviceID, Manufacturer, Model) mitkNewMacro3Param(Self, int, std::string, std::string); // To open A VideoFile (Path, Manufacturer, Model) mitkNewMacro3Param(Self, std::string, std::string, std::string); // To open a device (DeviceID, Metadata) mitkNewMacro2Param(Self, int, mitk::USImageMetadata::Pointer); // To open A VideoFile (Path, Metadata) mitkNewMacro2Param(Self, std::string, mitk::USImageMetadata::Pointer); /** * \return the qualified name of this class (as returned by GetDeviceClassStatic()) */ std::string GetDeviceClass() override; /** * This methode is necessary instead of a static member attribute to avoid * "static initialization order fiasco" when an instance of this class is * used in a module activator. * * \return the qualified name of this class */ static std::string GetDeviceClassStatic(); /** * Getter for the custom control interface which was created during the * construction process of mitk::USVideoDevice. * * \return custom control interface of the video device */ itk::SmartPointer GetControlInterfaceCustom() override; /** * \brief Remove this device from the micro service. * This method is public for mitk::USVideoDevice, 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(); /** * \return mitk::USImageSource connected to this device */ USImageSource::Pointer GetUSImageSource() override; /** * \brief Return all probes for this USVideoDevice or an empty vector it no probes were set * Returns a std::vector of all probes that exist for this USVideoDevice if there were probes set while creating or modifying this USVideoDevice. * Otherwise it returns an empty vector. Therefore always check if vector is filled, before using it! */ std::vector GetAllProbes(); /** * \brief Cleans the std::vector containing all configured probes. */ void DeleteAllProbes(); /** * \brief Return current active probe for this USVideoDevice * Returns a pointer to the probe that is currently in use. If there were probes set while creating or modifying this USVideoDevice. * Returns null otherwise */ mitk::USProbe::Pointer GetCurrentProbe(); /** \brief adds a new probe to the device */ void AddNewProbe(mitk::USProbe::Pointer probe); /** * \brief get the probe by its name * Returns a pointer to the probe identified by the given name. If no probe of given name exists for this Device 0 is returned. */ mitk::USProbe::Pointer GetProbeByName(std::string name); /** * \brief Removes the Probe with the given name */ void RemoveProbeByName(std::string name); /** \brief True, if this Device plays back a file, false if it recieves data from a device */ bool GetIsSourceFile(); /** * \brief Sets the first existing probe or the default probe of the video device * as the current probe of it. */ void SetDefaultProbeAsCurrentProbe(); /** * \brief Sets the probe with the given name as current probe if the named probe exists. */ void SetCurrentProbe( std::string probename ); /** * \brief Sets the given spacing of the current depth of the current probe. */ void SetSpacing( double xSpacing, double ySpacing ) override; itkGetMacro(ImageVector, std::vector); itkGetMacro(DeviceID, int); itkGetMacro(FilePath, std::string); protected: /** * \brief Creates a new device that will deliver USImages taken from a video device. * under windows, try -1 for device number, which will grab the first available one * (Open CV functionality) */ USVideoDevice(int videoDeviceNumber, std::string manufacturer, std::string model); /** * \brief Creates a new device that will deliver USImages taken from a video file. */ USVideoDevice(std::string videoFilePath, std::string manufacturer, std::string model); /** * \brief Creates a new device that will deliver USImages taken from a video device. * under windows, try -1 for device number, which will grab the first available one * (Open CV functionality) */ USVideoDevice(int videoDeviceNumber, mitk::USImageMetadata::Pointer metadata); /** * \brief Creates a new device that will deliver USImages taken from a video file. */ USVideoDevice(std::string videoFilePath, mitk::USImageMetadata::Pointer metadata); ~USVideoDevice() override; /** * \brief Initializes common properties for all constructors. */ void Init(); /** * \brief Is called during the initialization process. * Returns true if successful and false if unsuccessful. Additionally, you may throw an exception to clarify what went wrong. */ bool OnInitialization() override; /** * \brief Is called during the connection process. * Returns true if successful and false if unsuccessful. Additionally, you may throw an exception to clarify what went wrong. */ bool OnConnection() override; /** * \brief Is called during the disconnection process. * Returns true if successful and false if unsuccessful. Additionally, you may throw an exception to clarify what went wrong. */ bool OnDisconnection() override; /** * \brief Is called during the activation process. After this method is finsihed, the device should be generating images */ bool OnActivation() override; /** * \brief Is called during the deactivation process. After a call to this method the device should still be connected, but not producing images anymore. */ bool OnDeactivation() override; /** * \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; + /** + * \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; + /** * \brief The image source that we use to aquire data */ mitk::USImageVideoSource::Pointer m_Source; /** * \brief True, if this source plays back a file, false if it recieves data from a device */ bool m_SourceIsFile; /** * \brief The device id to connect to. Undefined, if m_SourceIsFile == true; */ int m_DeviceID; /** * \brief The Filepath id to connect to. Undefined, if m_SourceIsFile == false; */ std::string m_FilePath; /** * \brief custom control interface for us video device */ itk::SmartPointer m_ControlInterfaceCustom; /** * \brief probes for this USVideoDevice */ std::vector < mitk::USProbe::Pointer > m_Probes; /** \brief probe that is currently in use */ mitk::USProbe::Pointer m_CurrentProbe; }; } // namespace mitk #endif // MITKUSVideoDevice_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..0b77d91b58 100644 --- a/Modules/US/USNavigation/files.cmake +++ b/Modules/US/USNavigation/files.cmake @@ -1,5 +1,7 @@ SET(CPP_FILES mitkUSCombinedModality.cpp + mitkTrackedUltrasound.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..8bb5a8975b --- /dev/null +++ b/Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.cpp @@ -0,0 +1,473 @@ +/*=================================================================== + +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 "mitkNavigationDataDisplacementFilter.h" +#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::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_DisplacementFilter(mitk::NavigationDataDisplacementFilter::New()), + m_LastFilterOfIGTPipeline(nullptr), + m_NumberOfSmoothingValues(0), m_DelayCount(0), + m_IsTrackedUltrasoundActive( trackedUltrasoundActive ) +{ + m_DisplacementFilter->SetTransform6DOF(true); + + 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() +{ + if( m_LastFilterOfIGTPipeline.IsNull() ) + { + this->RebuildFilterPipeline(); + } + return m_LastFilterOfIGTPipeline; +} + +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); +} + +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; +} + +void mitk::AbstractUltrasoundTrackerDevice::RebuildFilterPipeline() +{ + m_LastFilterOfIGTPipeline = m_TrackingDeviceDataSource; + + if( m_NumberOfSmoothingValues > 0 ) + { + m_SmoothingFilter->ConnectTo(m_LastFilterOfIGTPipeline.GetPointer()); + m_LastFilterOfIGTPipeline = m_SmoothingFilter; + } + + if( m_DelayCount > 0 ) + { + m_DelayFilter->ConnectTo(m_LastFilterOfIGTPipeline.GetPointer()); + m_LastFilterOfIGTPipeline = m_DelayFilter; + } + + if( m_IsTrackedUltrasoundActive ) + { + m_DisplacementFilter->ConnectTo(m_LastFilterOfIGTPipeline.GetPointer()); + m_LastFilterOfIGTPipeline = m_DisplacementFilter; + } +} + +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); +} + +mitk::USAbstractControlInterface::Pointer mitk::AbstractUltrasoundTrackerDevice::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::AbstractUltrasoundTrackerDevice::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::AbstractUltrasoundTrackerDevice::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::AbstractUltrasoundTrackerDevice::GetControlInterfaceDoppler() +{ + if (m_UltrasoundDevice.IsNull()) + { + MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; + mitkThrow() << "UltrasoundDevice must not be null."; + } + + return m_UltrasoundDevice->GetControlInterfaceDoppler(); +} diff --git a/Modules/US/USNavigation/mitkUSCombinedModality.h b/Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.h similarity index 51% copy from Modules/US/USNavigation/mitkUSCombinedModality.h copy to Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.h index a549299f54..8e0f8bf705 100644 --- a/Modules/US/USNavigation/mitkUSCombinedModality.h +++ b/Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.h @@ -1,256 +1,257 @@ /*=================================================================== 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; + class NavigationDataDisplacementFilter; /** - * \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); + + itkGetMacro(IsTrackedUltrasoundActive, bool); /** * \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. */ - std::string GetDeviceClass() override; + std::string GetDeviceClass(); /** * \brief Wrapper for returning USImageSource of the UltrasoundDevice. */ - USImageSource::Pointer GetUSImageSource() override; + USImageSource::Pointer GetUSImageSource(); - /** - * \brief Wrapper for returning custom control interface of the UltrasoundDevice. - */ - itk::SmartPointer GetControlInterfaceCustom() override; - - /** - * \brief Wrapper for returning B mode control interface of the UltrasoundDevice. - */ - itk::SmartPointer GetControlInterfaceBMode() override; - - /** - * \brief Wrapper for returning probes control interface of the UltrasoundDevice. - */ - 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 */ - 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 = ""); - ~USCombinedModality() override; + void UnregisterOnService(); - /** - * \brief Initializes UltrasoundDevice. - */ - bool OnInitialization() override; + virtual void RegisterAsMicroservice(); /** - * \brief Connects UltrasoundDevice. + * \brief Wrapper for returning custom control interface of the UltrasoundDevice. */ - bool OnConnection() override; + virtual itk::SmartPointer GetControlInterfaceCustom(); /** - * \brief Disconnects UltrasoundDevice. + * \brief Wrapper for returning B mode control interface of the UltrasoundDevice. */ - bool OnDisconnection() override; + virtual itk::SmartPointer GetControlInterfaceBMode(); /** - * \brief Activates UltrasoundDevice. + * \brief Wrapper for returning probes control interface of the UltrasoundDevice. */ - bool OnActivation() override; + virtual itk::SmartPointer GetControlInterfaceProbes(); /** - * \brief Deactivates UltrasoundDevice. + * \brief Wrapper for returning doppler control interface of the UltrasoundDevice. */ - bool OnDeactivation() override; + virtual itk::SmartPointer GetControlInterfaceDoppler(); + + protected: + AbstractUltrasoundTrackerDevice( USDevice::Pointer usDevice, + itk::SmartPointer trackingDevice, + bool trackedUltrasoundActive ); + virtual ~AbstractUltrasoundTrackerDevice(); - /** - * \brief Freezes or unfreezes UltrasoundDevice. - */ - void OnFreeze(bool) override; /** * \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(); 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; + itk::SmartPointer m_DisplacementFilter; + itk::SmartPointer m_LastFilterOfIGTPipeline; unsigned int m_NumberOfSmoothingValues; unsigned int m_DelayCount; + /** + * \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/mitkTrackedUltrasound.cpp b/Modules/US/USNavigation/mitkTrackedUltrasound.cpp new file mode 100644 index 0000000000..2e0b8cda28 --- /dev/null +++ b/Modules/US/USNavigation/mitkTrackedUltrasound.cpp @@ -0,0 +1,83 @@ +/*=================================================================== + +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 "mitkTrackedUltrasound.h" +#include "mitkImageReadAccessor.h" +#include +#include +#include "mitkNavigationDataDisplacementFilter.h" +#include "mitkTrackingDeviceSource.h" + + + + +mitk::TrackedUltrasound::TrackedUltrasound( USDevice::Pointer usDevice, + NavigationDataSource::Pointer trackingDevice, + bool trackedUltrasoundActive ) + : AbstractUltrasoundTrackerDevice( usDevice, trackingDevice, trackedUltrasoundActive ) +{ +} + +mitk::TrackedUltrasound::~TrackedUltrasound() +{ +} + +void mitk::TrackedUltrasound::GenerateData() +{ + //Call Update auf US-Device + evtl. auf Tracker (???) + + if (m_UltrasoundDevice->GetIsFreezed()) { return; } //if the image is freezed: do nothing + + //get next image from ultrasound image source + //FOR LATER: Be aware if the for loop behaves correct, if the UltrasoundDevice has more than 1 output. + int i = 0; + mitk::Image::Pointer image = m_UltrasoundDevice->GetUSImageSource()->GetNextImage().at(i); + + if (image.IsNull() || !image->IsInitialized()) //check the image + { + mitk::Image::Pointer image = m_UltrasoundDevice->GetOutput(i); + if (image.IsNull() || !image->IsInitialized()) //check the image + { + MITK_WARN << "Invalid image in TrackedUltrasound, aborting!"; + return; + } + //___MITK_INFO << "GetSpacing: " << image->GetGeometry()->GetSpacing(); + + //get output and initialize it if it wasn't initialized before + mitk::Image::Pointer output = this->GetOutput(i); + 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 + m_DisplacementFilter->SetTransformation(calibrationIterator->second); + //Setze Update auf Displacementfilter ???? + } + } +} diff --git a/Modules/US/USNavigation/mitkTrackedUltrasound.h b/Modules/US/USNavigation/mitkTrackedUltrasound.h new file mode 100644 index 0000000000..e05f650bd5 --- /dev/null +++ b/Modules/US/USNavigation/mitkTrackedUltrasound.h @@ -0,0 +1,66 @@ +/*=================================================================== + +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 __mitkTrackedUltrasound_h +#define __mitkTrackedUltrasound_h + +#include +#include "mitkUSDevice.h" +#include "mitkImageSource.h" +#include "mitkAbstractUltrasoundTrackerDevice.h" +#include "mitkNavigationDataSource.h" + +namespace itk { + template class SmartPointer; +} + +namespace mitk { + + /** + * \brief Combination of USDevice and 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 TrackedUltrasound : public mitk::AbstractUltrasoundTrackerDevice + { + public: + + mitkClassMacro(TrackedUltrasound, mitk::AbstractUltrasoundTrackerDevice); + mitkNewMacro3Param(TrackedUltrasound, USDevice::Pointer, itk::SmartPointer, bool); + + + + + protected: + TrackedUltrasound( USDevice::Pointer usDevice, + itk::SmartPointer trackingDevice, + bool trackedUltrasoundActive = true ); + virtual ~TrackedUltrasound(); + + /** + * \brief Grabs the next frame from the input. + * This method is called internally, whenever Update() is invoked by an Output. + */ + void GenerateData() override; + + }; +} // namespace mitk +#endif // __mitkTrackedUltrasound_h diff --git a/Modules/US/USNavigation/mitkUSCombinedModality.cpp b/Modules/US/USNavigation/mitkUSCombinedModality.cpp index 7c1baf9f71..307a8e5d52 100644 --- a/Modules/US/USNavigation/mitkUSCombinedModality.cpp +++ b/Modules/US/USNavigation/mitkUSCombinedModality.cpp @@ -1,576 +1,362 @@ /*=================================================================== 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 "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() { } -std::string mitk::USCombinedModality::GetDeviceClass() -{ - return DeviceClassIdentifier; -} mitk::USImageSource::Pointer mitk::USCombinedModality::GetUSImageSource() { if (m_UltrasoundDevice.IsNull()) { MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; mitkThrow() << "UltrasoundDevice must not be null."; } 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(); } mitk::USDevice::UnregisterOnService(); } 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) { // 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 nullptr; } return calibrationIterator->second; } void mitk::USCombinedModality::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::USCombinedModality::RemoveCalibration() { return this->RemoveCalibration(this->GetCurrentDepthValue(), this->GetIdentifierForCurrentProbe()); } bool mitk::USCombinedModality::RemoveCalibration(std::string depth) { return this->RemoveCalibration(depth, this->GetIdentifierForCurrentProbe()); } bool mitk::USCombinedModality::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::USCombinedModality::ProbeAndDepthSeperator + depth; return m_Calibrations.erase(calibrationKey) > 0; } void mitk::USCombinedModality::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::USCombinedModality::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); } bool mitk::USCombinedModality::OnInitialization() { 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; } } bool mitk::USCombinedModality::OnConnection() { 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(); } } bool mitk::USCombinedModality::OnDisconnection() { if (m_UltrasoundDevice.IsNull()) { MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; mitkThrow() << "UltrasoundDevice must not be null."; } 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()) { 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(); } void mitk::USCombinedModality::OnFreeze(bool freeze) { 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::NavigationDataSource::Pointer mitk::USCombinedModality::GetNavigationDataSource() { return m_LastFilter.GetPointer(); } bool mitk::USCombinedModality::GetIsCalibratedForCurrentStatus() { return m_Calibrations.find(this->GetIdentifierForCurrentCalibration()) != m_Calibrations.end(); } bool mitk::USCombinedModality::GetContainsAtLeastOneCalibration() { return !m_Calibrations.empty(); } void mitk::USCombinedModality::GenerateData() { 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()[0]; - + //FOR LATER: Be aware if the for loop behaves correct, if the UltrasoundDevice has more than 1 output. + int i = 0; + mitk::Image::Pointer image = m_UltrasoundDevice->GetUSImageSource()->GetNextImage().at(i); 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); } } } - -std::string mitk::USCombinedModality::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::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(); - - // 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; - } -} - -std::string mitk::USCombinedModality::GetIdentifierForCurrentCalibration() -{ - return this->GetIdentifierForCurrentProbe() - + mitk::USCombinedModality::ProbeAndDepthSeperator - + this->GetCurrentDepthValue(); -} - -std::string mitk::USCombinedModality::GetIdentifierForCurrentProbe() -{ - 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; -} - -std::string mitk::USCombinedModality::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::USCombinedModality::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH); - - if (depthIterator != usdeviceProperties.end()) - { - depth = depthIterator->second.ToString(); - } - else - { - depth = "0"; - } - - return depth; -} - -void mitk::USCombinedModality::RebuildFilterPipeline() -{ - 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; - } -} - -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); -} diff --git a/Modules/US/USNavigation/mitkUSCombinedModality.h b/Modules/US/USNavigation/mitkUSCombinedModality.h index a549299f54..d148f1d653 100644 --- a/Modules/US/USNavigation/mitkUSCombinedModality.h +++ b/Modules/US/USNavigation/mitkUSCombinedModality.h @@ -1,256 +1,255 @@ /*=================================================================== 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" 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. */ std::string GetDeviceClass() override; /** * \brief Wrapper for returning USImageSource of the UltrasoundDevice. */ USImageSource::Pointer GetUSImageSource() override; /** * \brief Wrapper for returning custom control interface of the UltrasoundDevice. */ itk::SmartPointer GetControlInterfaceCustom() override; /** * \brief Wrapper for returning B mode control interface of the UltrasoundDevice. */ itk::SmartPointer GetControlInterfaceBMode() override; /** * \brief Wrapper for returning probes control interface of the UltrasoundDevice. */ itk::SmartPointer GetControlInterfaceProbes() override; /** * \brief Wrapper for returning doppler control interface of the UltrasoundDevice. */ 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 ); ~USCombinedModality() override; /** * \brief Initializes UltrasoundDevice. */ bool OnInitialization() override; /** * \brief Connects UltrasoundDevice. */ bool OnConnection() override; /** * \brief Disconnects UltrasoundDevice. */ bool OnDisconnection() override; /** * \brief Activates UltrasoundDevice. */ bool OnActivation() override; /** * \brief Deactivates UltrasoundDevice. */ bool OnDeactivation() override; /** * \brief Freezes or unfreezes UltrasoundDevice. */ void OnFreeze(bool) 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; }; } // namespace mitk //MITK_DECLARE_SERVICE_INTERFACE(mitk::USCombinedModality, "org.mitk.services.USCombinedModality") #endif // MITKUSCombinedModality_H_HEADER_INCLUDED_ diff --git a/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.cpp b/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.cpp index 7c3dcfdbb3..c88d5bff0a 100644 --- a/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.cpp +++ b/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.cpp @@ -1,811 +1,812 @@ /*=================================================================== 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. ===================================================================*/ //#define _USE_MATH_DEFINES #include // QT headers #include #include // mitk headers // itk headers #include #include const std::string QmitkUSNewVideoDeviceWidget::VIEW_ID = "org.mitk.views.QmitkUSNewVideoDeviceWidget"; QmitkUSNewVideoDeviceWidget::QmitkUSNewVideoDeviceWidget(QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f) { m_Controls = nullptr; CreateQtPartControl(this); } QmitkUSNewVideoDeviceWidget::~QmitkUSNewVideoDeviceWidget() {} //////////////////// INITIALIZATION ///////////////////// void QmitkUSNewVideoDeviceWidget::CreateQtPartControl(QWidget* parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkUSNewVideoDeviceWidgetControls; m_Controls->setupUi(parent); this->CreateConnections(); } } void QmitkUSNewVideoDeviceWidget::CreateConnections() { if (m_Controls) { // connect(m_Controls->m_BtnDone, SIGNAL(clicked()), this, // SLOT(OnClickedDone())); connect(m_Controls->m_BtnCancel, SIGNAL(clicked()), this, SLOT(OnClickedCancel())); connect(m_Controls->m_RadioDeviceSource, SIGNAL(clicked()), this, SLOT(OnDeviceTypeSelection())); connect(m_Controls->m_RadioFileSource, SIGNAL(clicked()), this, SLOT(OnDeviceTypeSelection())); connect(m_Controls->m_RadioOIGTLClientSource, SIGNAL(clicked()), this, SLOT(OnDeviceTypeSelection())); connect(m_Controls->m_RadioOIGTLServerSource, SIGNAL(clicked()), this, SLOT(OnDeviceTypeSelection())); connect(m_Controls->m_OpenFileButton, SIGNAL(clicked()), this, SLOT(OnOpenFileButtonClicked())); connect(m_Controls->m_BtnSave, SIGNAL(clicked()), this, SLOT(OnSaveButtonClicked())); connect(m_Controls->m_BtnLoadConfiguration, SIGNAL(clicked()), this, SLOT(OnLoadConfigurationButtonClicked())); //Connect buttons and functions for editing of probes connect(m_Controls->m_AddNewProbePushButton, SIGNAL(clicked()), this, SLOT(OnAddNewProbeClicked())); connect(m_Controls->m_BtnRemoveProbe, SIGNAL(clicked()), this, SLOT(OnClickedRemoveProbe())); connect(m_Controls->m_BtnRemoveDepth, SIGNAL(clicked()), this, SLOT(OnClickedRemoveDepth())); connect(m_Controls->m_BtnAddDepths, SIGNAL(clicked()), this, SLOT(OnClickedAddDepths())); connect(m_Controls->m_Probes, SIGNAL(currentTextChanged(const QString &)), this, SLOT(OnProbeChanged(const QString &))); connect(m_Controls->m_Depths, SIGNAL(currentTextChanged(const QString &)), this, SLOT(OnDepthChanged(const QString &))); connect(m_Controls->m_XSpacingSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnXSpacingSpinBoxChanged(double))); connect(m_Controls->m_YSpacingSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnYSpacingSpinBoxChanged(double))); connect(m_Controls->m_CroppingTopSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnCroppingTopSpinBoxChanged(int))); connect(m_Controls->m_CroppingRightSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnCroppingRightSpinBoxChanged(int))); connect(m_Controls->m_CroppingBottomSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnCroppingBottomSpinBoxChanged(int))); connect(m_Controls->m_CroppingLeftSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnCroppingLeftSpinBoxChanged(int))); } } ///////////// Methods & Slots Handling Direct Interaction ///////////////// void QmitkUSNewVideoDeviceWidget::OnClickedDone() { m_Active = false; // Create Device mitk::USVideoDevice::Pointer newDevice; if (m_Controls->m_RadioDeviceSource->isChecked()) { newDevice = mitk::USVideoDevice::New( m_Controls->m_DeviceSelector->value(), m_Controls->m_Manufacturer->text().toStdString(), m_Controls->m_Model->text().toStdString()); newDevice->SetComment(m_Controls->m_Comment->text().toStdString()); } else if (m_Controls->m_RadioFileSource->isChecked()) { newDevice = mitk::USVideoDevice::New( m_Controls->m_FilePathSelector->text().toStdString(), m_Controls->m_Manufacturer->text().toStdString(), m_Controls->m_Model->text().toStdString()); newDevice->SetComment(m_Controls->m_Comment->text().toStdString()); } else if (m_Controls->m_RadioOIGTLClientSource->isChecked()) { std::string host = m_Controls->m_OIGTLClientHost->text().toStdString(); int port = m_Controls->m_OIGTLClientPort->value(); // Create a new USIGTLDevice. The last parameter tells the device that it should be a client. mitk::USIGTLDevice::Pointer device = mitk::USIGTLDevice::New(m_Controls->m_Manufacturer->text().toStdString(), m_Controls->m_Model->text().toStdString(), host, port, false); device->Initialize(); emit Finished(); // The rest of this method does stuff that is specific to USVideoDevices, // which we don't need. So we return directly. return; } else { std::string host = m_Controls->m_OIGTLServerHost->text().toStdString(); int port = m_Controls->m_OIGTLServerPort->value(); // Create a new USIGTLDevice. The last parameter tells the device that it should be a server. mitk::USIGTLDevice::Pointer device = mitk::USIGTLDevice::New(m_Controls->m_Manufacturer->text().toStdString(), m_Controls->m_Model->text().toStdString(), host, port, true); device->Initialize(); emit Finished(); // The rest of this method does stuff that is specific to USVideoDevices, // which we don't need. So we return directly. return; } // get USImageVideoSource from new device mitk::USImageVideoSource::Pointer imageSource = dynamic_cast( newDevice->GetUSImageSource().GetPointer()); if (!imageSource) { MITK_ERROR << "There is no USImageVideoSource at the current device."; mitkThrow() << "There is no USImageVideoSource at the current device."; } // Set Video Options imageSource->SetColorOutput(!m_Controls->m_CheckGreyscale->isChecked()); // If Resolution override is activated, apply it if (m_Controls->m_CheckResolutionOverride->isChecked()) { int width = m_Controls->m_ResolutionWidth->value(); int height = m_Controls->m_ResolutionHeight->value(); imageSource->OverrideResolution(width, height); imageSource->SetResolutionOverride(true); } if (m_Controls->m_Probes->count() != 0 ) //there are informations about the probes of the device, so create the probes { this->AddProbesToDevice(newDevice); } else //no information about the probes of the device, so set default value { mitk::USProbe::Pointer probe = mitk::USProbe::New("default"); probe->SetDepth(0); newDevice->DeleteAllProbes(); newDevice->AddNewProbe(probe); } newDevice->Initialize(); CleanUpAfterCreatingNewDevice(); emit Finished(); } void QmitkUSNewVideoDeviceWidget::OnClickedFinishedEditing() { m_Active = false; m_TargetDevice->SetManufacturer(m_Controls->m_Manufacturer->text().toStdString()); m_TargetDevice->SetName(m_Controls->m_Model->text().toStdString()); m_TargetDevice->SetComment(m_Controls->m_Comment->text().toStdString()); if (m_Controls->m_Probes->count() != 0) //there are informations about the probes of the device, so create the probes { this->AddProbesToDevice(m_TargetDevice); } else //no information about the probes of the device, so set default value { mitk::USProbe::Pointer probe = mitk::USProbe::New("default"); probe->SetDepth(0); m_TargetDevice->DeleteAllProbes(); m_TargetDevice->AddNewProbe(probe); } mitk::USImageVideoSource::Pointer imageSource = dynamic_cast( m_TargetDevice->GetUSImageSource().GetPointer()); if (!imageSource) { MITK_ERROR << "There is no USImageVideoSource at the current device."; mitkThrow() << "There is no USImageVideoSource at the current device."; } // Set Video Options imageSource->SetColorOutput(!m_Controls->m_CheckGreyscale->isChecked()); // If Resolution override is activated, apply it if (m_Controls->m_CheckResolutionOverride->isChecked()) { int width = m_Controls->m_ResolutionWidth->value(); int height = m_Controls->m_ResolutionHeight->value(); imageSource->OverrideResolution(width, height); imageSource->SetResolutionOverride(true); } CleanUpAfterEditingOfDevice(); MITK_INFO << "Finished Editing"; emit Finished(); } void QmitkUSNewVideoDeviceWidget::OnClickedCancel() { m_TargetDevice = nullptr; m_Active = false; CleanUpAfterCreatingNewDevice(); CleanUpAfterEditingOfDevice(); emit Finished(); } void QmitkUSNewVideoDeviceWidget::OnDeviceTypeSelection() { m_Controls->m_FilePathSelector->setEnabled( m_Controls->m_RadioFileSource->isChecked()); m_Controls->m_DeviceSelector->setEnabled( m_Controls->m_RadioDeviceSource->isChecked()); m_Controls->m_OIGTLClientHost->setEnabled( m_Controls->m_RadioOIGTLClientSource->isChecked()); m_Controls->m_OIGTLClientPort->setEnabled( m_Controls->m_RadioOIGTLClientSource->isChecked()); m_Controls->m_OIGTLServerHost->setEnabled( m_Controls->m_RadioOIGTLServerSource->isChecked()); m_Controls->m_OIGTLServerPort->setEnabled( m_Controls->m_RadioOIGTLServerSource->isChecked()); } void QmitkUSNewVideoDeviceWidget::OnOpenFileButtonClicked() { QString fileName = QFileDialog::getOpenFileName(nullptr, "Open Video File"); if (fileName.isNull()) { return; } // user pressed cancel m_Controls->m_FilePathSelector->setText(fileName); m_Controls->m_RadioFileSource->setChecked(true); this->OnDeviceTypeSelection(); } ///////////////// Methods & Slots Handling Logic ////////////////////////// void QmitkUSNewVideoDeviceWidget::EditDevice(mitk::USDevice::Pointer device) { // If no VideoDevice is given, throw an exception if (device->GetDeviceClass().compare("org.mitk.modules.us.USVideoDevice") != 0) { // TODO Alert if bad path mitkThrow() << "NewVideoDeviceWidget recieved an incompatible device type " "to edit. Type was: " << device->GetDeviceClass(); } m_TargetDevice = static_cast(device.GetPointer()); m_Active = true; m_ConfigProbes.clear(); m_ConfigProbes = m_TargetDevice->GetAllProbes(); ChangeUIEditingUSVideoDevice(); } void QmitkUSNewVideoDeviceWidget::CreateNewDevice() { //Toggle functionality of Btn_Done connect(m_Controls->m_BtnDone, SIGNAL(clicked()), this, SLOT(OnClickedDone())); m_Controls->m_BtnDone->setText("Add Video Device"); //Fill Metadata with default information m_Controls->m_Manufacturer->setText("Unknown Manufacturer"); m_Controls->m_Model->setText("Unknown Model"); m_Controls->m_Comment->setText("None"); m_TargetDevice = nullptr; m_ConfigProbes.clear(); + m_ConfigProbes.clear(); m_Active = true; } /////////////////////// HOUSEHOLDING CODE /////////////////////////////// QListWidgetItem* QmitkUSNewVideoDeviceWidget::ConstructItemFromDevice( mitk::USDevice::Pointer device) { QListWidgetItem* result = new QListWidgetItem; std::string text = device->GetManufacturer() + "|" + device->GetName(); result->setText(text.c_str()); return result; } void QmitkUSNewVideoDeviceWidget::ChangeUIEditingUSVideoDevice() { for (std::vector::iterator it = m_ConfigProbes.begin(); it != m_ConfigProbes.end(); it++) { std::string probeName = (*it)->GetName(); m_Controls->m_Probes->addItem(QString::fromUtf8(probeName.data(), probeName.size())); } OnProbeChanged(m_Controls->m_Probes->currentText()); //Toggle functionality of Btn_Done m_Controls->m_BtnDone->setText("Apply Changes"); connect(m_Controls->m_BtnDone, SIGNAL(clicked()), this, SLOT(OnClickedFinishedEditing())); //Fill Metadata with Information provided by the Device selected to edit m_Controls->m_Manufacturer->setText(m_TargetDevice->GetManufacturer().c_str()); m_Controls->m_Model->setText(m_TargetDevice->GetName().c_str()); m_Controls->m_Comment->setText(m_TargetDevice->GetComment().c_str()); } void QmitkUSNewVideoDeviceWidget::OnClickedAddDepths() { if (!m_Controls->m_Probes->currentText().isEmpty()) { QString depths = m_Controls->m_AddDepths->text(); if( depths.isEmpty() ) return; std::string probename = m_Controls->m_Probes->currentText().toStdString(); mitk::USProbe::Pointer currentProbe = this->CheckIfProbeExistsAlready(probename); QStringList singleDepths = depths.split(','); for (int i = 0; i < singleDepths.size(); i++) { currentProbe->SetDepth(singleDepths.at(i).toInt()); } m_Controls->m_AddDepths->clear(); m_Controls->m_Depths->setEnabled(true); m_Controls->m_BtnRemoveDepth->setEnabled(true); OnProbeChanged(m_Controls->m_Probes->currentText()); } } void QmitkUSNewVideoDeviceWidget::OnClickedRemoveDepth() { if (!m_Controls->m_Probes->currentText().isEmpty() && !m_Controls->m_Depths->currentText().isEmpty()) { std::string probename = m_Controls->m_Probes->currentText().toStdString(); int indexOfDepthToRemove = m_Controls->m_Depths->currentIndex(); mitk::USProbe::Pointer currentProbe = this->CheckIfProbeExistsAlready(probename); currentProbe->RemoveDepth(m_Controls->m_Depths->currentText().toInt()); m_Controls->m_Depths->removeItem(indexOfDepthToRemove); if (m_Controls->m_Depths->count() == 0) { m_Controls->m_Depths->setEnabled(false); m_Controls->m_BtnRemoveDepth->setEnabled(false); this->EnableDisableSpacingAndCropping(false); } } } void QmitkUSNewVideoDeviceWidget::OnClickedRemoveProbe() { if (!m_Controls->m_Probes->currentText().isEmpty()) { std::string probename = m_Controls->m_Probes->currentText().toStdString(); int indexOfProbeToRemove = m_Controls->m_Probes->currentIndex(); m_ConfigProbes.erase(m_ConfigProbes.begin() + indexOfProbeToRemove); m_Controls->m_Probes->removeItem(indexOfProbeToRemove); if( m_Controls->m_Probes->count() == 0 ) { m_Controls->m_Probes->setEnabled(false); m_Controls->m_BtnRemoveProbe->setEnabled(false); m_Controls->m_BtnAddDepths->setEnabled(false); m_Controls->m_AddDepths->setEnabled(false); m_Controls->m_Depths->setEnabled(false); m_Controls->m_BtnRemoveDepth->setEnabled(false); this->EnableDisableSpacingAndCropping(false); } } } void QmitkUSNewVideoDeviceWidget::OnProbeChanged(const QString & probename) { if (!probename.isEmpty()) { std::string name = probename.toStdString(); mitk::USProbe::Pointer probe = this->CheckIfProbeExistsAlready(name); if( probe.IsNotNull() ) { std::map depths = probe->GetDepthsAndSpacing(); m_Controls->m_Depths->clear(); for (std::map::iterator it = depths.begin(); it != depths.end(); it++) { m_Controls->m_Depths->addItem(QString::number(it->first)); } this->OnDepthChanged(m_Controls->m_Depths->currentText().toInt(), probe); } } else { m_Controls->m_Depths->clear(); m_Controls->m_Depths->setEnabled(false); m_Controls->m_BtnRemoveDepth->setEnabled(false); } } void QmitkUSNewVideoDeviceWidget::OnDepthChanged(int depth, mitk::USProbe::Pointer probe) { if (m_Controls->m_Depths->count() == 0) { m_Controls->m_Depths->setEnabled(false); m_Controls->m_BtnRemoveDepth->setEnabled(false); this->EnableDisableSpacingAndCropping(false); return; } if (probe.IsNotNull()) { mitk::Vector3D spacing = probe->GetSpacingForGivenDepth(depth); m_Controls->m_XSpacingSpinBox->setValue(spacing[0]); m_Controls->m_YSpacingSpinBox->setValue(spacing[1]); mitk::USProbe::USProbeCropping cropping = probe->GetProbeCropping(); m_Controls->m_CroppingTopSpinBox->setValue(cropping.top); m_Controls->m_CroppingRightSpinBox->setValue(cropping.right); m_Controls->m_CroppingBottomSpinBox->setValue(cropping.bottom); m_Controls->m_CroppingLeftSpinBox->setValue(cropping.left); this->EnableDisableSpacingAndCropping(true); m_Controls->m_Depths->setEnabled(true); m_Controls->m_BtnRemoveDepth->setEnabled(true); m_Controls->m_AddDepths->setEnabled(true); m_Controls->m_BtnAddDepths->setEnabled(true); m_Controls->m_Probes->setEnabled(true); m_Controls->m_BtnRemoveProbe->setEnabled(true); } } void QmitkUSNewVideoDeviceWidget::OnDepthChanged(const QString &depth) { MITK_INFO << "OnDepthChanged(int, mitk::USProbe)"; if( depth.isEmpty() ) { this->EnableDisableSpacingAndCropping(false); return; } QString probeName = m_Controls->m_Probes->currentText(); this->OnDepthChanged(depth.toInt(), this->CheckIfProbeExistsAlready(probeName.toStdString()) ); } void QmitkUSNewVideoDeviceWidget::OnSaveButtonClicked() { QString fileName = QFileDialog::getSaveFileName(nullptr, "Save Configuration ...", "", "XML files (*.xml)"); if( fileName.isNull() ) { return; } // user pressed cancel mitk::USDeviceWriterXML deviceWriter; deviceWriter.SetFilename(fileName.toStdString()); mitk::USDeviceReaderXML::USVideoDeviceConfigData config; this->CollectUltrasoundVideoDeviceConfigInformation(config); if (!deviceWriter.WriteUltrasoundVideoDeviceConfiguration(config)) { QMessageBox msgBox; msgBox.setText("Error when writing the configuration to the selected file. Could not write device information."); msgBox.exec(); return; } } void QmitkUSNewVideoDeviceWidget::OnLoadConfigurationButtonClicked() { QString fileName = QFileDialog::getOpenFileName(this, "Open ultrasound device configuration ..."); if (fileName.isNull()) { return; } // user pressed cancel mitk::USDeviceReaderXML deviceReader; deviceReader.SetFilename(fileName.toStdString()); if (!deviceReader.ReadUltrasoundDeviceConfiguration()) { QMessageBox msgBox; msgBox.setText("Error when parsing the selected file. Could not load stored device information."); msgBox.exec(); return; } mitk::USDeviceReaderXML::USVideoDeviceConfigData config = deviceReader.GetUSVideoDeviceConfigData(); if( config.fileversion == 1.0 ) { if (config.deviceType.compare("video") == 0) { //Fill info in metadata groupbox: m_Controls->m_DeviceName->setText(QString::fromStdString(config.deviceName)); m_Controls->m_Manufacturer->setText(QString::fromStdString(config.manufacturer)); m_Controls->m_Model->setText(QString::fromStdString(config.model)); m_Controls->m_Comment->setText(QString::fromStdString(config.comment)); //Fill info about video source: m_Controls->m_DeviceSelector->setValue(config.sourceID); m_Controls->m_FilePathSelector->setText(QString::fromStdString(config.filepathVideoSource)); //Fill video options: m_Controls->m_CheckGreyscale->setChecked(config.useGreyscale); //Fill override options: m_Controls->m_CheckResolutionOverride->setChecked(config.useResolutionOverride); m_Controls->m_ResolutionWidth->setValue(config.resolutionWidth); m_Controls->m_ResolutionHeight->setValue(config.resolutionHeight); //Fill information about probes: m_ConfigProbes.clear(); m_ConfigProbes = config.probes; m_Controls->m_Probes->clear(); m_Controls->m_ProbeNameLineEdit->clear(); m_Controls->m_AddDepths->clear(); m_Controls->m_Depths->clear(); for( size_t index = 0; index < m_ConfigProbes.size(); ++index) { m_Controls->m_Probes->addItem(QString::fromStdString(config.probes.at(index)->GetName())); } this->OnProbeChanged(m_Controls->m_Probes->currentText()); } else { MITK_WARN << "Unknown device type detected. The device type must be of type |video|"; } } else { MITK_WARN << "Unknown fileversion. Only fileversion 1.0 is known to the system."; } } void QmitkUSNewVideoDeviceWidget::OnAddNewProbeClicked() { QString probeName = m_Controls->m_ProbeNameLineEdit->text(); probeName = probeName.trimmed(); if (probeName.isEmpty()) { m_Controls->m_ProbeNameLineEdit->clear(); return; } if( this->CheckIfProbeExistsAlready(probeName.toStdString() ) != nullptr ) { QMessageBox msgBox; msgBox.setText("Probe name already exists. Please choose another name for the probe."); msgBox.exec(); m_Controls->m_ProbeNameLineEdit->clear(); } else { mitk::USProbe::Pointer newProbe = mitk::USProbe::New(probeName.toStdString()); m_ConfigProbes.push_back(newProbe); m_Controls->m_Probes->addItem(QString::fromStdString(probeName.toStdString())); m_Controls->m_Probes->setEnabled(true); m_Controls->m_BtnRemoveProbe->setEnabled(true); m_Controls->m_BtnAddDepths->setEnabled(true); m_Controls->m_AddDepths->setEnabled(true); m_Controls->m_ProbeNameLineEdit->clear(); } } void QmitkUSNewVideoDeviceWidget::OnXSpacingSpinBoxChanged(double value) { MITK_INFO << "Changing x-spacing to: " << value; QString probeName = m_Controls->m_Probes->currentText(); int depth = m_Controls->m_Depths->currentText().toInt(); mitk::USProbe::Pointer probe = this->CheckIfProbeExistsAlready(probeName.toStdString()); if (probe.IsNull()) { QMessageBox msgBox; msgBox.setText("An error occurred when changing the spacing. \ The specified probe does not exist. \ Please restart the configuration process."); msgBox.exec(); return; } mitk::Vector3D spacing = probe->GetSpacingForGivenDepth(depth); spacing[0] = value; probe->SetSpacingForGivenDepth(depth, spacing); } void QmitkUSNewVideoDeviceWidget::OnYSpacingSpinBoxChanged(double value) { MITK_INFO << "Changing y-spacing to: " << value; QString probeName = m_Controls->m_Probes->currentText(); int depth = m_Controls->m_Depths->currentText().toInt(); mitk::USProbe::Pointer probe = this->CheckIfProbeExistsAlready(probeName.toStdString()); if (probe.IsNull()) { QMessageBox msgBox; msgBox.setText("An error occurred when changing the spacing. \ The specified probe does not exist. \ Please restart the configuration process."); msgBox.exec(); return; } mitk::Vector3D spacing = probe->GetSpacingForGivenDepth(depth); spacing[1] = value; probe->SetSpacingForGivenDepth(depth, spacing); } void QmitkUSNewVideoDeviceWidget::OnCroppingTopSpinBoxChanged(int value) { MITK_INFO << "Changing cropping top to: " << value; QString probeName = m_Controls->m_Probes->currentText(); mitk::USProbe::Pointer probe = this->CheckIfProbeExistsAlready(probeName.toStdString()); if (probe.IsNull()) { QMessageBox msgBox; msgBox.setText("An error occurred when changing the probe cropping. \ The specified probe does not exist. \ Please restart the configuration process."); msgBox.exec(); return; } mitk::USProbe::USProbeCropping cropping = probe->GetProbeCropping(); probe->SetProbeCropping(value, cropping.bottom, cropping.left, cropping.right); } void QmitkUSNewVideoDeviceWidget::OnCroppingRightSpinBoxChanged(int value) { MITK_INFO << "Changing cropping right to: " << value; QString probeName = m_Controls->m_Probes->currentText(); mitk::USProbe::Pointer probe = this->CheckIfProbeExistsAlready(probeName.toStdString()); if (probe.IsNull()) { QMessageBox msgBox; msgBox.setText("An error occurred when changing the probe cropping. \ The specified probe does not exist. \ Please restart the configuration process."); msgBox.exec(); return; } mitk::USProbe::USProbeCropping cropping = probe->GetProbeCropping(); probe->SetProbeCropping(cropping.top, cropping.bottom, cropping.left, value); } void QmitkUSNewVideoDeviceWidget::OnCroppingBottomSpinBoxChanged(int value) { MITK_INFO << "Changing cropping bottom to: " << value; QString probeName = m_Controls->m_Probes->currentText(); mitk::USProbe::Pointer probe = this->CheckIfProbeExistsAlready(probeName.toStdString()); if (probe.IsNull()) { QMessageBox msgBox; msgBox.setText("An error occurred when changing the probe cropping. \ The specified probe does not exist. \ Please restart the configuration process."); msgBox.exec(); return; } mitk::USProbe::USProbeCropping cropping = probe->GetProbeCropping(); probe->SetProbeCropping(cropping.top, value, cropping.left, cropping.right); } void QmitkUSNewVideoDeviceWidget::OnCroppingLeftSpinBoxChanged(int value) { MITK_INFO << "Changing cropping left to: " << value; QString probeName = m_Controls->m_Probes->currentText(); mitk::USProbe::Pointer probe = this->CheckIfProbeExistsAlready(probeName.toStdString()); if (probe.IsNull()) { QMessageBox msgBox; msgBox.setText("An error occurred when changing the probe cropping. \ The specified probe does not exist. \ Please restart the configuration process."); msgBox.exec(); return; } mitk::USProbe::USProbeCropping cropping = probe->GetProbeCropping(); probe->SetProbeCropping(cropping.top, cropping.bottom, value, cropping.right); } void QmitkUSNewVideoDeviceWidget::CleanUpAfterCreatingNewDevice() { disconnect(m_Controls->m_BtnDone, SIGNAL(clicked()), this, SLOT(OnClickedDone())); m_Controls->m_Probes->clear(); m_Controls->m_Depths->clear(); m_Controls->m_AddDepths->clear(); m_Controls->m_ProbeNameLineEdit->clear(); m_ConfigProbes.clear(); } void QmitkUSNewVideoDeviceWidget::CleanUpAfterEditingOfDevice() { disconnect(m_Controls->m_BtnDone, SIGNAL(clicked()), this, SLOT(OnClickedFinishedEditing())); m_Controls->m_Probes->clear(); m_Controls->m_Depths->clear(); m_Controls->m_AddDepths->clear(); m_ConfigProbes.clear(); } void QmitkUSNewVideoDeviceWidget::AddProbesToDevice(mitk::USVideoDevice::Pointer device) { device->DeleteAllProbes(); for( std::vector::iterator it = m_ConfigProbes.begin(); it != m_ConfigProbes.end(); it++) { if ((*it)->IsDepthAndSpacingEmpty()) { (*it)->SetDepth(0); } device->AddNewProbe((*it)); } } mitk::USProbe::Pointer QmitkUSNewVideoDeviceWidget::CheckIfProbeExistsAlready(const std::string &probeName) { for( std::vector::iterator it = m_ConfigProbes.begin(); it != m_ConfigProbes.end(); it++ ) { if( probeName.compare((*it)->GetName()) == 0) return (*it); } return nullptr; //no matching probe was found so nullptr is returned } void QmitkUSNewVideoDeviceWidget::CollectUltrasoundVideoDeviceConfigInformation(mitk::USDeviceReaderXML::USVideoDeviceConfigData &config) { config.fileversion = 1.0; config.deviceType = "video"; //Fill info in metadata groupbox: config.deviceName = m_Controls->m_DeviceName->text().toStdString(); config.manufacturer = m_Controls->m_Manufacturer->text().toStdString(); config.model = m_Controls->m_Model->text().toStdString(); config.comment = m_Controls->m_Comment->text().toStdString(); //Fill info about video source: config.sourceID = m_Controls->m_DeviceSelector->value(); config.filepathVideoSource = m_Controls->m_FilePathSelector->text().toStdString(); //Fill video options: config.useGreyscale = m_Controls->m_CheckGreyscale->isChecked(); //Fill override options: config.useResolutionOverride = m_Controls->m_CheckResolutionOverride->isChecked(); config.resolutionWidth = m_Controls->m_ResolutionWidth->value(); config.resolutionHeight = m_Controls->m_ResolutionHeight->value(); //Fill information about probes: config.probes = m_ConfigProbes; } void QmitkUSNewVideoDeviceWidget::EnableDisableSpacingAndCropping(bool enable) { m_Controls->m_XSpacingSpinBox->setEnabled(enable); m_Controls->m_YSpacingSpinBox->setEnabled(enable); m_Controls->m_XSpacingLabel->setEnabled(enable); m_Controls->m_YSpacingLabel->setEnabled(enable); m_Controls->m_CroppingTopSpinBox->setEnabled(enable); m_Controls->m_CroppingRightSpinBox->setEnabled(enable); m_Controls->m_CroppingBottomSpinBox->setEnabled(enable); m_Controls->m_CroppingLeftSpinBox->setEnabled(enable); m_Controls->m_CroppingTopLabel->setEnabled(enable); m_Controls->m_CroppingBottomLabel->setEnabled(enable); m_Controls->m_CroppingLeftLabel->setEnabled(enable); m_Controls->m_CroppingRightLabel->setEnabled(enable); } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/files.cmake b/Plugins/org.mitk.gui.qt.igt.app.echotrack/files.cmake index a980a60ba8..c7bf3f73ac 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/files.cmake +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/files.cmake @@ -1,136 +1,132 @@ set(SRC_CPP_FILES ) set(INTERNAL_CPP_FILES org_mbi_gui_qt_usnavigation_Activator.cpp #USNavigation.cpp //not functional anymore. Delete code? QmitkUltrasoundCalibration.cpp QmitkUSNavigationMarkerPlacement.cpp QmitkUSNavigationPerspective.cpp mitkUSTargetPlacementQualityCalculator.cpp QmitkUSZonesDataModel.cpp QmitkUSNavigationCalibrationsDataModel.cpp QmitkUSZoneManagementColorDialogDelegate.cpp QmitkUSNavigationCalibrationRemoveDelegate.cpp QmitkUSNavigationCalibrationUpdateDepthDelegate.cpp Interactors/mitkUSZonesInteractor.cpp Interactors/mitkUSPointMarkInteractor.cpp Widgets/QmitkUSCombinedModalityCreationWidget.cpp Widgets/QmitkUSCombinedModalityEditWidget.cpp Widgets/QmitkUSNavigationFreezeButton.cpp - Widgets/QmitkUSNavigationProcessWidget.cpp Widgets/QmitkUSNavigationZoneDistancesWidget.cpp Widgets/QmitkUSZoneManagementWidget.cpp Widgets/QmitkZoneProgressBar.cpp NavigationStepWidgets/QmitkUSAbstractNavigationStep.cpp NavigationStepWidgets/QmitkUSNavigationStepCombinedModality.cpp NavigationStepWidgets/QmitkUSNavigationStepTumourSelection.cpp NavigationStepWidgets/QmitkUSNavigationStepZoneMarking.cpp NavigationStepWidgets/QmitkUSNavigationStepPlacementPlanning.cpp NavigationStepWidgets/QmitkUSNavigationStepMarkerIntervention.cpp NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.cpp SettingsWidgets/QmitkUSNavigationCombinedSettingsWidget.cpp SettingsWidgets/QmitkUSNavigationAbstractSettingsWidget.cpp Filter/mitkUSNavigationTargetOcclusionFilter.cpp Filter/mitkUSNavigationTargetUpdateFilter.cpp Filter/mitkUSNavigationTargetIntersectionFilter.cpp IO/mitkUSNavigationCombinedModalityPersistence.cpp IO/mitkUSNavigationLoggingBackend.cpp IO/mitkUSNavigationExperimentLogging.cpp IO/mitkUSNavigationStepTimer.cpp ) set(UI_FILES #src/internal/USNavigationControls.ui //not functional anymore. Delete code? src/internal/QmitkUltrasoundCalibrationControls.ui src/internal/QmitkUSNavigationMarkerPlacement.ui src/internal/Widgets/QmitkUSCombinedModalityCreationWidget.ui src/internal/Widgets/QmitkUSCombinedModalityEditWidget.ui - src/internal/Widgets/QmitkUSNavigationProcessWidget.ui src/internal/Widgets/QmitkUSZoneManagementWidget.ui src/internal/NavigationStepWidgets/QmitkUSAbstractNavigationStep.ui src/internal/NavigationStepWidgets/QmitkUSNavigationStepCombinedModality.ui src/internal/NavigationStepWidgets/QmitkUSNavigationStepTumourSelection.ui src/internal/NavigationStepWidgets/QmitkUSNavigationStepZoneMarking.ui src/internal/NavigationStepWidgets/QmitkUSNavigationStepPlacementPlanning.ui src/internal/NavigationStepWidgets/QmitkUSNavigationStepMarkerIntervention.ui src/internal/NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.ui src/internal/SettingsWidgets/QmitkUSNavigationCombinedSettingsWidget.ui ) set(MOC_H_FILES src/internal/org_mbi_gui_qt_usnavigation_Activator.h - #src/internal/USNavigation.h //not functional anymore. Delete code? src/internal/QmitkUltrasoundCalibration.h src/internal/QmitkUSNavigationMarkerPlacement.h src/internal/QmitkUSZonesDataModel.h src/internal/QmitkUSNavigationCalibrationsDataModel.h src/internal/QmitkUSZoneManagementColorDialogDelegate.h src/internal/QmitkUSNavigationCalibrationRemoveDelegate.h src/internal/QmitkUSNavigationCalibrationUpdateDepthDelegate.h src/internal/QmitkUSNavigationPerspective.h src/internal/Widgets/QmitkUSCombinedModalityCreationWidget.h src/internal/Widgets/QmitkUSCombinedModalityEditWidget.h src/internal/Widgets/QmitkUSNavigationFreezeButton.h - src/internal/Widgets/QmitkUSNavigationProcessWidget.h src/internal/Widgets/QmitkUSNavigationZoneDistancesWidget.h src/internal/Widgets/QmitkUSZoneManagementWidget.h src/internal/Widgets/QmitkZoneProgressBar.h src/internal/NavigationStepWidgets/QmitkUSAbstractNavigationStep.h src/internal/NavigationStepWidgets/QmitkUSNavigationStepCombinedModality.h src/internal/NavigationStepWidgets/QmitkUSNavigationStepTumourSelection.h src/internal/NavigationStepWidgets/QmitkUSNavigationStepZoneMarking.h src/internal/NavigationStepWidgets/QmitkUSNavigationStepPlacementPlanning.h src/internal/NavigationStepWidgets/QmitkUSNavigationStepMarkerIntervention.h src/internal/NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.h src/internal/SettingsWidgets/QmitkUSNavigationCombinedSettingsWidget.h src/internal/SettingsWidgets/QmitkUSNavigationAbstractSettingsWidget.h ) # list of resource files which can be used by the plug-in # system without loading the plug-ins shared library, # for example the icon used in the menu and tabs for the # plug-in views in the workbench set(CACHED_RESOURCE_FILES resources/icon_US_navigation.svg resources/icon_US_calibration.svg plugin.xml ) # list of Qt .qrc files which contain additional resources # specific to this plugin set(QRC_FILES resources/USNavigation.qrc ) set(CPP_FILES ) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) set(RESOURCE_FILES Interactions/USPointMarkInteractions.xml Interactions/USZoneInteractions.xml Interactions/USZoneInteractionsHold.xml ) 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..6cf3cb256b 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"; + MITK_WARN << "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 8ad60d0537..f57d51e3a2 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 #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 vtkSmartPointer vtkSphere = vtkSmartPointer::New(); vtkSphere->SetRadius(5); vtkSphere->SetCenter(0, 0, 0); vtkSphere->Update(); zone->SetVtkPolyData(vtkSphere->GetOutput()); // 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 b86f9595d3..bcf772e00d 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,816 +1,816 @@ /*=================================================================== 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 #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 vtkSmartPointer vtkSphere = vtkSmartPointer::New(); vtkSphere->SetRadius(5); vtkSphere->SetCenter(0, 0, 0); vtkSphere->Update(); surface->SetVtkPolyData(vtkSphere->GetOutput()); 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 db3c0c8b0c..035a7266e5 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,427 +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 "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); 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 3cc40c3395..9ab674beda 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,874 +1,687 @@ /*=================================================================== 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" #include // 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 vtkSmartPointer vtkSphere = vtkSmartPointer::New(); vtkSphere->SetRadius(newSize / 2); vtkSphere->SetCenter(0, 0, 0); vtkSphere->SetPhiResolution(20); vtkSphere->SetThetaResolution(20); vtkSphere->Update(); mitk::Surface::Pointer zoneSurface = dynamic_cast(m_AblationZonesVector.at(id)->GetData()); zoneSurface->SetVtkPolyData(vtkSphere->GetOutput()); } 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 vtkSmartPointer vtkSphere = vtkSmartPointer::New(); vtkSphere->SetRadius(size / 2); vtkSphere->SetCenter(0, 0, 0); vtkSphere->SetPhiResolution(20); vtkSphere->SetThetaResolution(20); vtkSphere->Update(); zone->SetVtkPolyData(vtkSphere->GetOutput()); // 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))); + m_BaseNode = this->GetDataStorage()->GetNamedNode(QmitkUSAbstractNavigationStep::DATANAME_BASENODE); + if (m_BaseNode.IsNull()) + { + m_BaseNode = mitk::DataNode::New(); + m_BaseNode->SetName(QmitkUSAbstractNavigationStep::DATANAME_BASENODE); + this->GetDataStorage()->Add(m_BaseNode); + } - 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); - ui->navigationProcessWidget->SetSettingsWidget(new QmitkUSNavigationCombinedSettingsWidget(m_Parent)); + connect(ui->m_settingsWidget, SIGNAL(SettingsChanged(itk::SmartPointer)), this, SLOT(OnSettingsChanged(itk::SmartPointer))); + +} + +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..416c97632b 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,205 @@ /*=================================================================== 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_BaseNode; + 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..953bcaad53 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,251 @@ QmitkUSNavigationMarkerPlacement 0 0 - 443 - 146 + 562 + 446 Form - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - + - - - - - - Qt::Horizontal + + + true + + + 0 + + + Initialization + + + + + + + + + + Navigation Control + + + + + + 0 + + + + + 0 + 0 + 93 + 57 + + + + Target + + + + + + Initialize + + + + + + + + + + + + 0 + 0 + 93 + 57 + + + + Critical Structures + + + + + + Initialize + + + + + + + + + + + + 0 + 0 + 93 + 57 + + + + Needle Insertion + + + + + + Initialize + + + + + + + + + + + + + + + Settings + + + + + + + + + Qt::Horizontal + + + + + + + + + Enable Navigation Render Window Layout with RenderWindow + + + true + + + + + + + 1 + + + 3 + + + + + + + Refresh view + + + + + + + + + Qt::Horizontal + + + + + + + false + + + Finish Experiment + + + + + + + Start New Experiment + + + + + - - - - - Enable Navigation Render Window Layout with RenderWindow - - - true - - - - - - - 1 - - - 3 - - - - - - - Refresh view - - - - - - - - - - - Start New Experiment - - - - - - - false - - - Finish Experiment - - - - - - - - 20 - 20 - - - - - - - - + + + + 20 + 20 + + + + + + - QmitkUSNavigationProcessWidget + 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/Widgets/QmitkUSNavigationProcessWidget.h
+
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 e817742768..60b1c22bd5 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,1155 +1,1158 @@ /*=================================================================== 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, "OnDeviceServiceEvent", 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::OnDeviceServiceEvent(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()) + + if( !m_CombinedModality->GetIsTrackedUltrasoundActive() ) { - transform->SetModeToSimilarity(); - } //use affine transform + if (m_Controls.m_ScaleTransform->isChecked()) + { + transform->SetModeToSimilarity(); + } //use affine transform + else + { + transform->SetModeToRigidBody(); + } //use similarity transform: scaling is not touched + MITK_INFO << "TEST"; + } else { - transform->SetModeToRigidBody(); - } //use similarity transform: scaling is not touched + 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); } + if( !m_CombinedModality->GetIsTrackedUltrasoundActive() ) + { + if( !m_Controls.m_ScaleTransform->isChecked() ) { m_Transformation->Compose(oldUSImageTransform); } + MITK_INFO << "Used old USImageTransform"; + } + 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); } + else + { + mitk::Image::Pointer m_Image = m_CombinedModality->GetUltrasoundDevice()->GetOutput(); + m_Node->SetData(m_Image); //Workaround because image is not initalized, maybe problem of the Ultrasound view? + } + m_CombinedModality->Modified(); + m_CombinedModality->Update(); // 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()) { if (!m_Timer->isActive()) // Activate Imaging { // if (m_Node) m_Node->ReleaseData(); if (m_CombinedModality.IsNull()) { m_Timer->stop(); return; } m_Timer->start(); } //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 { //deactivate Imaging m_Timer->stop(); m_CombinedModality->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; + m_CombinedModality->GetUltrasoundDevice()->SetSpacing(xSpacing, ySpacing); //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 a248221248..2f89c17461 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,344 @@ /*=================================================================== 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 OnDeviceServiceEvent(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..f93de764c0 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,92 @@ /*=================================================================== 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" +#include "mitkTrackedUltrasound.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"; } + if (name.isEmpty()) { name = "Ultrasound Tracker Device"; } + + if( ui->activateTrackedUSCheckbox->isChecked() ) + { + m_CombinedModality = mitk::TrackedUltrasound::New(usDevice, trackingDevice, true); + MITK_INFO << "Created TrackedUltrasound device"; + } + else + { + m_CombinedModality = mitk::USCombinedModality::New(usDevice, trackingDevice, false); + MITK_INFO << "Created CombinedModality device"; + } - mitk::USCombinedModality::Pointer combinedModality = mitk::USCombinedModality::New( - usDevice, trackingDevice, vendor.toStdString(), name.toStdString()); - combinedModality->Initialize(); - combinedModality->RegisterAsMicroservice(); // register as micro service + 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/QmitkUSCombinedModalityCreationWidget.ui b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityCreationWidget.ui index 8454199a6b..fddd41ad6f 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityCreationWidget.ui +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityCreationWidget.ui @@ -1,167 +1,174 @@ QmitkUSCombinedModalityCreationWidget 0 0 323 350 0 350 Form 75 true Ultrasound Devices: 0 0 0 0 75 true Tracking Devices: 0 0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Please select an ultrasound device and a tracking device from the lists above. These devices will be used to create a combined modality. Additionally, you may specifiy a vendor and a name.</span></p></body></html> true - - + + - Name + Vendor - - + + - Combined Modality + MBI - - + + - Vendor + Name - - + + - MBI + Combined Modality + + + + Activate Tracked Ultrasound + + + false Create Combined Modality :/USNavigation/accept.png:/USNavigation/accept.png Cancel :/USNavigation/restart.png:/USNavigation/restart.png QmitkServiceListWidget QWidget
QmitkServiceListWidget.h
1
SignalAborted()
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/QmitkUSCombinedModalityEditWidget.ui b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityEditWidget.ui index 85c8d9f55e..ad752a7e63 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityEditWidget.ui +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityEditWidget.ui @@ -1,343 +1,352 @@ QmitkUSCombinedModalityEditWidget 0 0 404 - 418 + 456 0 350 Form <html><head/><body><p><span style=" font-weight:600;">Identifier:</span></p></body></html> Name Vendor Qt::Vertical QSizePolicy::Fixed 20 10 75 true Ultrasound Device: Qt::Vertical QSizePolicy::Fixed 20 10 75 true Tracking Device: Qt::Vertical QSizePolicy::Fixed 20 10 <html><head/><body><p><span style=" font-weight:600;">Calibrations:</span></p></body></html> QFrame::StyledPanel QFrame::Sunken + + + 0 + 50 + + + + Qt::ScrollBarAlwaysOn + QAbstractItemView::NoSelection 80 15 true false Load Calibrations from File System Load :/USNavigation/document-open.png:/USNavigation/document-open.png Write Calibrations to File System Write :/USNavigation/document-save.png:/USNavigation/document-save.png Qt::Vertical QSizePolicy::Fixed 20 20 true OK :/USNavigation/accept.png:/USNavigation/accept.png Cancel :/USNavigation/restart.png:/USNavigation/restart.png saveButton clicked() QmitkUSCombinedModalityEditWidget OnSaveButtonClicked() 104 347 201 184 cancelButton clicked() QmitkUSCombinedModalityEditWidget OnCancelButtonClicked() 299 347 201 184 calibrationsSaveButton clicked() QmitkUSCombinedModalityEditWidget OnCalibrationsSaveButtonClicked() 201 348 201 208 calibrationsLoadButton clicked() QmitkUSCombinedModalityEditWidget OnCalibrationsLoadButtonClicked() 109 337 201 208 SignalAborted() OnSaveButtonClicked() OnCancelButtonClicked() OnCalibrationsSaveButtonClicked() OnCalibrationsLoadButtonClicked() 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 deleted file mode 100644 index 0ef68154c7..0000000000 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationProcessWidget.cpp +++ /dev/null @@ -1,557 +0,0 @@ -/*=================================================================== - -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); -} - -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() ) - { - 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 - - 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 - - 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) -{ - 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 deleted file mode 100644 index 1a78fd3998..0000000000 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationProcessWidget.h +++ /dev/null @@ -1,179 +0,0 @@ -/*=================================================================== - -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); - - /** - * \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); - - /** - * \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 OnSettingsChanged(const itk::SmartPointer); - -public: - typedef std::vector NavigationStepVector; - typedef NavigationStepVector::iterator NavigationStepIterator; - - explicit QmitkUSNavigationProcessWidget(QWidget* parent = 0); - ~QmitkUSNavigationProcessWidget(); - - /** - * \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_LastNavigationDataFilter; - - QWidget* m_Parent; - QSignalMapper* m_ReadySignalMapper; - QSignalMapper* m_NoLongerReadySignalMapper; - - QmitkStdMultiWidget* m_StdMultiWidget; - - bool m_UsePlanningStepWidget; - -private: - Ui::QmitkUSNavigationProcessWidget *ui; -}; - -#endif // USNAVIGATIONPROCESSWIDGET_H diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationProcessWidget.ui b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationProcessWidget.ui deleted file mode 100644 index 5526f413c9..0000000000 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationProcessWidget.ui +++ /dev/null @@ -1,203 +0,0 @@ - - - QmitkUSNavigationProcessWidget - - - - 0 - 0 - 465 - 757 - - - - Form - - - - - - - font-size: 10pt; - font-weight: bold; - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - 0 - - - - - - - - - - - - - false - - - Open Preferences - - - Preferences - - - - :/USNavigation/preferences.png:/USNavigation/preferences.png - - - - - - - false - - - false - - - Restart the Current Step - - - &Restart Step - - - - :/USNavigation/restart.png:/USNavigation/restart.png - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - false - - - Go to Previous Step - - - &Prev - - - - :/USNavigation/go-previous.png:/USNavigation/go-previous.png - - - - - - - false - - - Go to Next Step - - - &Next - - - - :/USNavigation/go-next.png:/USNavigation/go-next.png - - - - - - - - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Settings</span></p></body></html> - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - Save - - - - :/USNavigation/document-save.png:/USNavigation/document-save.png - - - - - - - Cancel - - - - :/USNavigation/restart.png:/USNavigation/restart.png - - - - - - - - - - - - - - - - OnNextButtonClicked() - OnPreviousButtonClicked() - OnRestartStepButtonClicked() - OnTabChanged(int) - -