diff --git a/Modules/US/USNavigation/Testing/mitkCombinedModalityTest.cpp b/Modules/US/USNavigation/Testing/mitkCombinedModalityTest.cpp index 0556c322ba..f7dc20005a 100644 --- a/Modules/US/USNavigation/Testing/mitkCombinedModalityTest.cpp +++ b/Modules/US/USNavigation/Testing/mitkCombinedModalityTest.cpp @@ -1,180 +1,180 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkUSCombinedModality.h" #include #include #include #include class mitkCombinedModalityTestClass { public: /* * \brief Returns a reference string for serialized calibrations. */ static std::string GetSerializedReference() { return std::string("\n<") + mitk::USCombinedModality::DefaultProbeIdentifier + mitk::USCombinedModality::ProbeAndDepthSeperator + "0 M00=\"1.1234\" M01=\"1.2234\" M02=\"1.3234\" M10=\"1.4234\" M11=\"1.5234\" M12=\"1.6234\" M20=\"1.7234\" M21=\"1.8234\" M22=\"1.9234\" T0=\"2.1234\" T1=\"2.2234\" T2=\"2.3234\" />\n\n"; } static bool CompareDoubles (double A, double B) { float diff = A - B; return (diff < 0.0001) && (-diff < 0.0001); } /* * \brief Creates a dummy combined modality. */ static mitk::USCombinedModality::Pointer CreateModality() { mitk::USVideoDevice::Pointer usDevice = mitk::USVideoDevice::New("IllegalPath", "Manufacturer", "Model"); mitk::VirtualTrackingDevice::Pointer tracker = mitk::VirtualTrackingDevice::New(); tracker->AddTool("tool1"); tracker->AddTool("tool2"); mitk::TrackingDeviceSource::Pointer source = mitk::TrackingDeviceSource::New(); source->SetTrackingDevice(tracker); source->Connect(); source->StartTracking(); - return mitk::USCombinedModality::New(usDevice.GetPointer(), source.GetPointer(), "MBI", "EchoTrack"); + return mitk::USCombinedModality::New(usDevice.GetPointer(), source.GetPointer(), false); } static void TestInstantiation() { mitk::USCombinedModality::Pointer combinedModality = CreateModality(); MITK_TEST_CONDITION_REQUIRED(combinedModality.IsNotNull(), "CombinedModality should not be null after instantiation"); } static void TestSerialization() { mitk::USCombinedModality::Pointer modality = CreateModality(); mitk::AffineTransform3D::MatrixType matrix; matrix[0][0] = 1.1234; matrix[0][1] = 1.2234; matrix[0][2] = 1.3234; matrix[1][0] = 1.4234; matrix[1][1] = 1.5234; matrix[1][2] = 1.6234; matrix[2][0] = 1.7234; matrix[2][1] = 1.8234; matrix[2][2] = 1.9234; mitk::AffineTransform3D::OffsetType offset; offset[0] = 2.1234; offset[1] = 2.2234; offset[2] = 2.3234; mitk::AffineTransform3D::Pointer transform = mitk::AffineTransform3D::New(); transform->SetMatrix(matrix); transform->SetOffset(offset); modality->SetCalibration(transform); MITK_TEST_CONDITION_REQUIRED(modality->SerializeCalibration() == GetSerializedReference(), "Testing correct Serialization..."); } static void TestDeserialization() { mitk::USCombinedModality::Pointer modality = CreateModality(); modality->DeserializeCalibration(GetSerializedReference()); mitk::AffineTransform3D::Pointer transform = modality->GetCalibration(); mitk::AffineTransform3D::MatrixType matrix = transform->GetMatrix(); mitk::AffineTransform3D::OffsetType offset = transform->GetOffset();; bool identical = true; if (! CompareDoubles(matrix[0][0], 1.1234)) identical = false; if (! CompareDoubles(matrix[0][1], 1.2234)) identical = false; if (! CompareDoubles(matrix[0][2], 1.3234)) identical = false; if (! CompareDoubles(matrix[1][0], 1.4234)) identical = false; if (! CompareDoubles(matrix[1][1], 1.5234)) identical = false; if (! CompareDoubles(matrix[1][2], 1.6234)) identical = false; if (! CompareDoubles(matrix[2][0], 1.7234)) identical = false; if (! CompareDoubles(matrix[2][1], 1.8234)) identical = false; if (! CompareDoubles(matrix[2][2], 1.9234)) identical = false; if (! CompareDoubles(offset[0], 2.1234)) identical = false; if (! CompareDoubles(offset[1], 2.2234)) identical = false; if (! CompareDoubles(offset[2], 2.3234)) identical = false; MITK_TEST_CONDITION_REQUIRED(identical, "Testing if deserialized calibration is identical to serialized one..."); // test if invalid strings cause exceptions MITK_TEST_FOR_EXCEPTION(mitk::Exception, modality->DeserializeCalibration("invalid-string")); MITK_TEST_FOR_EXCEPTION(mitk::Exception, modality->DeserializeCalibration("", false)); } static void TestFilterPipeline() { /*mitk::USCombinedModality::Pointer combinedModality = mitkCombinedModalityTestClass::CreateModality(); MITK_INFO << combinedModality->GetNavigationDataSource()->GetNameOfClass(); MITK_TEST_CONDITION(strcmp(combinedModality->GetNavigationDataSource()->GetNameOfClass(), "TrackingDeviceSource") == 0, "")*/ mitk::USVideoDevice::Pointer usDevice = mitk::USVideoDevice::New("IllegalPath", "Manufacturer", "Model"); mitk::VirtualTrackingDevice::Pointer tracker = mitk::VirtualTrackingDevice::New(); tracker->AddTool("tool1"); tracker->AddTool("tool2"); mitk::TrackingDeviceSource::Pointer source = mitk::TrackingDeviceSource::New(); source->SetTrackingDevice(tracker); source->Connect(); source->StartTracking(); - mitk::USCombinedModality::Pointer modality = mitk::USCombinedModality::New(usDevice.GetPointer(), source.GetPointer(), "MBI", "EchoTrack"); + mitk::USCombinedModality::Pointer modality = mitk::USCombinedModality::New(usDevice.GetPointer(), source.GetPointer(), false); MITK_TEST_CONDITION(source->GetOutput(0) == modality->GetNavigationDataSource()->GetOutput(0), "Navigation data output of the Combined Modality should be the same as the source output as no filters are active.") modality->SetNumberOfSmoothingValues(2); mitk::NavigationDataSource::Pointer smoothingFilter = modality->GetNavigationDataSource(); MITK_TEST_CONDITION(source->GetOutput(0) != smoothingFilter->GetOutput(0), "Navigation data output of the Combined Modality should be different to the source output as smoothing filter is active.") modality->SetNumberOfSmoothingValues(0); MITK_TEST_CONDITION(source->GetOutput(0) == modality->GetNavigationDataSource()->GetOutput(0), "Navigation data output of the Combined Modality should be the same as the source output again.") modality->SetDelayCount(5); MITK_TEST_CONDITION(source->GetOutput(0) != smoothingFilter->GetOutput(0), "Navigation data output of the Combined Modality should be different to the source output as delay filter is active.") modality->SetDelayCount(0); MITK_TEST_CONDITION(source->GetOutput(0) == modality->GetNavigationDataSource()->GetOutput(0), "Navigation data output of the Combined Modality should be the same as the source output again.") } }; /** * This function is testing methods of the class USDevice. */ int mitkCombinedModalityTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("mitkCombinedModalityTest"); mitkCombinedModalityTestClass::TestInstantiation(); mitkCombinedModalityTestClass::TestSerialization(); mitkCombinedModalityTestClass::TestDeserialization(); mitkCombinedModalityTestClass::TestFilterPipeline(); MITK_TEST_END(); } diff --git a/Modules/US/USNavigation/files.cmake b/Modules/US/USNavigation/files.cmake index b240daaede..8d3a527324 100644 --- a/Modules/US/USNavigation/files.cmake +++ b/Modules/US/USNavigation/files.cmake @@ -1,5 +1,6 @@ SET(CPP_FILES mitkUSCombinedModality.cpp + mitkAbstractUltrasoundTrackerDevice.cpp Filter/mitkNodeDisplacementFilter.cpp ) diff --git a/Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.cpp b/Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.cpp new file mode 100644 index 0000000000..45e7bedb82 --- /dev/null +++ b/Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.cpp @@ -0,0 +1,448 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkAbstractUltrasoundTrackerDevice.h" +#include "mitkImageReadAccessor.h" +#include "mitkNavigationDataSmoothingFilter.h" +#include "mitkNavigationDataDelayFilter.h" +#include "mitkTrackingDeviceSource.h" + +// US Control Interfaces +#include "mitkUSControlInterfaceProbes.h" +#include "mitkUSControlInterfaceBMode.h" +#include "mitkUSControlInterfaceDoppler.h" + +//Microservices +#include +#include +#include +#include + +#include + +//TempIncludes +#include + +const std::string mitk::AbstractUltrasoundTrackerDevice::DeviceClassIdentifier = "org.mitk.modules.us.AbstractUltrasoundTrackerDevice"; +const char* mitk::AbstractUltrasoundTrackerDevice::DefaultProbeIdentifier = "default"; +const char* mitk::AbstractUltrasoundTrackerDevice::ProbeAndDepthSeperator = "_"; +/* +const std::string mitk::AbstractUltrasoundTrackerDevice::US_INTERFACE_NAME = "org.mitk.services.AbstractUltrasoundTrackerDevice"; +const std::string mitk::AbstractUltrasoundTrackerDevice::US_PROPKEY_DEVICENAME = US_INTERFACE_NAME + ".devicename"; +const std::string mitk::AbstractUltrasoundTrackerDevice::US_PROPKEY_CLASS = US_INTERFACE_NAME + ".class"; +const std::string mitk::AbstractUltrasoundTrackerDevice::US_PROPKEY_ID = US_INTERFACE_NAME + ".id"; +*/ + + +mitk::AbstractUltrasoundTrackerDevice::AbstractUltrasoundTrackerDevice( + USDevice::Pointer usDevice, NavigationDataSource::Pointer trackingDevice, + bool trackedUltrasoundActive ) : + m_UltrasoundDevice(usDevice), m_TrackingDeviceDataSource(trackingDevice), + m_SmoothingFilter(mitk::NavigationDataSmoothingFilter::New()), + m_DelayFilter(mitk::NavigationDataDelayFilter::New(0)), + m_NumberOfSmoothingValues(0), m_DelayCount(0), + m_IsTrackedUltrasoundActive( trackedUltrasoundActive ) +{ + this->RebuildFilterPipeline(); + + //create a new output (for the image data) + mitk::Image::Pointer newOutput = mitk::Image::New(); + this->SetNthOutput(0, newOutput); + + // Combined Modality should not spawn an own acquire thread, because + // image acquiring is done by the included us device + m_UltrasoundDevice->SetSpawnAcquireThread(false); +} + + +mitk::AbstractUltrasoundTrackerDevice::~AbstractUltrasoundTrackerDevice() +{ + /*if( m_ServiceRegistration != nullptr ) + { + m_ServiceRegistration.Unregister(); + } + m_ServiceRegistration = 0;*/ +} + +mitk::AffineTransform3D::Pointer + mitk::AbstractUltrasoundTrackerDevice::GetCalibration() +{ + return this->GetCalibration( this->GetCurrentDepthValue(), + this->GetIdentifierForCurrentProbe() ); +} + +mitk::AffineTransform3D::Pointer + mitk::AbstractUltrasoundTrackerDevice::GetCalibration(std::string depth) +{ + return this->GetCalibration(depth, this->GetIdentifierForCurrentProbe()); +} + +mitk::AffineTransform3D::Pointer + mitk::AbstractUltrasoundTrackerDevice::GetCalibration( std::string depth, + std::string probe ) +{ + // make sure that there is no '/' which would cause problems for TinyXML + std::replace(probe.begin(), probe.end(), '/', '-'); + + // create identifier for calibration from probe and depth + std::string calibrationKey = + probe + + mitk::AbstractUltrasoundTrackerDevice::ProbeAndDepthSeperator + + depth; + + // find calibration for combination of probe identifier and depth + std::map::iterator calibrationIterator + = m_Calibrations.find(calibrationKey); + + if (calibrationIterator == m_Calibrations.end()) { return 0; } + + return calibrationIterator->second; +} + +void mitk::AbstractUltrasoundTrackerDevice::SetCalibration( + mitk::AffineTransform3D::Pointer calibration ) +{ + if( calibration.IsNull() ) + { + MITK_WARN << "Null pointer passed to SetCalibration of mitk::USDevice. Ignoring call."; + return; + } + + std::string calibrationKey = this->GetIdentifierForCurrentCalibration(); + if( calibrationKey.empty() ) + { + MITK_WARN << "Could not get a key for the calibration -> Calibration cannot be set."; + return; + } + + m_Calibrations[calibrationKey] = calibration; +} + +bool mitk::AbstractUltrasoundTrackerDevice::RemoveCalibration() +{ + return this->RemoveCalibration( this->GetCurrentDepthValue(), + this->GetIdentifierForCurrentProbe() ); +} + +bool mitk::AbstractUltrasoundTrackerDevice::RemoveCalibration(std::string depth) +{ + return this->RemoveCalibration( depth, + this->GetIdentifierForCurrentProbe() ); +} + +bool mitk::AbstractUltrasoundTrackerDevice::RemoveCalibration( std::string depth, + std::string probe ) +{ + // make sure that there is no '/' which would cause problems for TinyXML + std::replace(probe.begin(), probe.end(), '/', '-'); + + // create identifier for calibration from probe and depth + std::string calibrationKey = + probe + + mitk::AbstractUltrasoundTrackerDevice::ProbeAndDepthSeperator + + depth; + + return m_Calibrations.erase(calibrationKey) > 0; +} + +std::string mitk::AbstractUltrasoundTrackerDevice::GetDeviceClass() +{ + return DeviceClassIdentifier; +} + +mitk::USImageSource::Pointer mitk::AbstractUltrasoundTrackerDevice::GetUSImageSource() +{ + if (m_UltrasoundDevice.IsNull()) + { + MITK_ERROR("AbstractUltrasoundTrackerDevice")("USDevice") << "UltrasoundDevice must not be null."; + mitkThrow() << "UltrasoundDevice must not be null."; + } + + return m_UltrasoundDevice->GetUSImageSource(); +} + +mitk::NavigationDataSource::Pointer mitk::AbstractUltrasoundTrackerDevice::GetNavigationDataSource() +{ + return this->RebuildFilterPipeline(); +} + +bool mitk::AbstractUltrasoundTrackerDevice::GetIsCalibratedForCurrentStatus() +{ + return m_Calibrations.find(this->GetIdentifierForCurrentCalibration()) != m_Calibrations.end(); +} + +bool mitk::AbstractUltrasoundTrackerDevice::GetContainsAtLeastOneCalibration() +{ + return !m_Calibrations.empty(); +} + +std::string mitk::AbstractUltrasoundTrackerDevice::SerializeCalibration() +{ + std::stringstream result; + result << "" << std::endl; + // For each calibration in the set + for( std::map::iterator it = m_Calibrations.begin(); + it != m_Calibrations.end(); it++ ) + { + mitk::AffineTransform3D::MatrixType matrix = it->second->GetMatrix(); + mitk::AffineTransform3D::TranslationType translation = it->second->GetTranslation(); + TiXmlElement elem(it->first); + // Serialize Matrix + elem.SetDoubleAttribute("M00", matrix[0][0]); + elem.SetDoubleAttribute("M01", matrix[0][1]); + elem.SetDoubleAttribute("M02", matrix[0][2]); + elem.SetDoubleAttribute("M10", matrix[1][0]); + elem.SetDoubleAttribute("M11", matrix[1][1]); + elem.SetDoubleAttribute("M12", matrix[1][2]); + elem.SetDoubleAttribute("M20", matrix[2][0]); + elem.SetDoubleAttribute("M21", matrix[2][1]); + elem.SetDoubleAttribute("M22", matrix[2][2]); + // Serialize Offset + elem.SetDoubleAttribute("T0", translation[0]); + elem.SetDoubleAttribute("T1", translation[1]); + elem.SetDoubleAttribute("T2", translation[2]); + + result << elem << std::endl; + } + result << "" << std::endl; + + return result.str(); +} + +void mitk::AbstractUltrasoundTrackerDevice::DeserializeCalibration( + const std::string& xmlString, + bool clearPreviousCalibrations ) +{ + // Sanitize Input + if (xmlString == "") + { + MITK_ERROR << "Empty string passed to Deserialize() method of CombinedModality. Aborting..."; + mitkThrow() << "Empty string passed to Deserialize() method of CombinedModality. Aborting..."; + return; + } + // Clear previous calibrations if necessary + if (clearPreviousCalibrations) m_Calibrations.clear(); + + // Parse Input + TiXmlDocument doc; + if (!doc.Parse(xmlString.c_str())) + { + MITK_ERROR << "Unable to deserialize calibrations in CombinedModality. Error was: " << doc.ErrorDesc(); + mitkThrow() << "Unable to deserialize calibrations in CombinedModality. Error was: " << doc.ErrorDesc(); + return; + } + TiXmlElement* root = doc.FirstChildElement(); + if (root == nullptr) + { + MITK_ERROR << "Unable to deserialize calibrations in CombinedModality. String contained no root element."; + mitkThrow() << "Unable to deserialize calibrations in CombinedModality. String contained no root element."; + return; + } + // Read Calibrations + for (TiXmlElement* elem = root->FirstChildElement(); elem != nullptr; elem = elem->NextSiblingElement()) + { + mitk::AffineTransform3D::MatrixType matrix; + mitk::AffineTransform3D::OffsetType translation; + + std::string calibName = elem->Value(); + + // Deserialize Matrix + elem->QueryDoubleAttribute("M00", &matrix[0][0]); + elem->QueryDoubleAttribute("M01", &matrix[0][1]); + elem->QueryDoubleAttribute("M02", &matrix[0][2]); + elem->QueryDoubleAttribute("M10", &matrix[1][0]); + elem->QueryDoubleAttribute("M11", &matrix[1][1]); + elem->QueryDoubleAttribute("M12", &matrix[1][2]); + elem->QueryDoubleAttribute("M20", &matrix[2][0]); + elem->QueryDoubleAttribute("M21", &matrix[2][1]); + elem->QueryDoubleAttribute("M22", &matrix[2][2]); + + // Deserialize Offset + elem->QueryDoubleAttribute("T0", &translation[0]); + elem->QueryDoubleAttribute("T1", &translation[1]); + elem->QueryDoubleAttribute("T2", &translation[2]); + + mitk::AffineTransform3D::Pointer calibration = mitk::AffineTransform3D::New(); + calibration->SetMatrix(matrix); + calibration->SetTranslation(translation); + m_Calibrations[calibName] = calibration; + } +} + +void mitk::AbstractUltrasoundTrackerDevice::SetNumberOfSmoothingValues( + unsigned int numberOfSmoothingValues ) +{ + unsigned int oldNumber = m_NumberOfSmoothingValues; + m_NumberOfSmoothingValues = numberOfSmoothingValues; + + // if filter should be activated or deactivated + if ((oldNumber == 0 && numberOfSmoothingValues != 0) || + (oldNumber != 0 && numberOfSmoothingValues == 0)) + { + this->RebuildFilterPipeline(); + } + m_SmoothingFilter->SetNumerOfValues(numberOfSmoothingValues); +} + +void mitk::AbstractUltrasoundTrackerDevice::SetDelayCount( unsigned int delayCount ) +{ + unsigned int oldCount = m_DelayCount; + m_DelayCount = delayCount; + + // if filter should be activated or deactivated + if ((oldCount == 0 && delayCount != 0) || + (oldCount != 0 && delayCount == 0)) + { + this->RebuildFilterPipeline(); + } + m_DelayFilter->SetDelay(delayCount); +} + +void mitk::AbstractUltrasoundTrackerDevice::RegisterAsMicroservice() +{ +} + +itk::SmartPointer mitk::AbstractUltrasoundTrackerDevice::GetControlInterfaceCustom() +{ + return itk::SmartPointer(); +} + +itk::SmartPointer mitk::AbstractUltrasoundTrackerDevice::GetControlInterfaceBMode() +{ + return itk::SmartPointer(); +} + +itk::SmartPointer mitk::AbstractUltrasoundTrackerDevice::GetControlInterfaceProbes() +{ + return itk::SmartPointer(); +} + +itk::SmartPointer mitk::AbstractUltrasoundTrackerDevice::GetControlInterfaceDoppler() +{ + return itk::SmartPointer(); +} + +/*void mitk::AbstractUltrasoundTrackerDevice::UnregisterOnService() +{ + if( m_UltrasoundDevice->GetDeviceState() == USDevice::State_Activated ) + { + m_UltrasoundDevice->Deactivate(); + } + if( m_UltrasoundDevice->GetDeviceState() == USDevice::State_Connected ) + { + m_UltrasoundDevice->Disconnect(); + } + + if( m_ServiceRegistration != nullptr ) + m_ServiceRegistration.Unregister(); + m_ServiceRegistration = 0; +} + +void mitk::AbstractUltrasoundTrackerDevice::RegisterAsMicroservice() +{ + //Get Context + us::ModuleContext* context = us::GetModuleContext(); + + //Define ServiceProps + //us::ServiceProperties props; + mitk::UIDGenerator uidGen = + mitk::UIDGenerator("TEST", 16); + m_ServiceProperties[US_PROPKEY_ID] = uidGen.GetUID(); + m_ServiceProperties[US_PROPKEY_DEVICENAME] = m_UltrasoundDevice->GetName(); + m_ServiceProperties[US_PROPKEY_CLASS] = mitk::AbstractUltrasoundTrackerDevice::DeviceClassIdentifier; + + m_ServiceRegistration = context->RegisterService(this, m_ServiceProperties); +}*/ + +void mitk::AbstractUltrasoundTrackerDevice::GenerateData() +{ + +} + + +std::string mitk::AbstractUltrasoundTrackerDevice::GetIdentifierForCurrentCalibration() +{ + return this->GetIdentifierForCurrentProbe() + + mitk::AbstractUltrasoundTrackerDevice::ProbeAndDepthSeperator + + this->GetCurrentDepthValue(); +} + +std::string mitk::AbstractUltrasoundTrackerDevice::GetIdentifierForCurrentProbe() +{ + us::ServiceProperties usdeviceProperties = m_UltrasoundDevice->GetServiceProperties(); + + us::ServiceProperties::const_iterator probeIt = usdeviceProperties.find( + mitk::USDevice::GetPropertyKeys().US_PROPKEY_PROBES_SELECTED); + + // get probe identifier from control interface for probes + std::string probeName = mitk::AbstractUltrasoundTrackerDevice::DefaultProbeIdentifier; + if (probeIt != usdeviceProperties.end()) + { + probeName = (probeIt->second).ToString(); + } + + // make sure that there is no '/' which would cause problems for TinyXML + std::replace(probeName.begin(), probeName.end(), '/', '-'); + + return probeName; +} + +std::string mitk::AbstractUltrasoundTrackerDevice::GetCurrentDepthValue() +{ + us::ServiceProperties usdeviceProperties = m_UltrasoundDevice->GetServiceProperties(); + + // get string for depth value from the micro service properties + std::string depth; + us::ServiceProperties::iterator depthIterator = usdeviceProperties.find( + mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH); + + if (depthIterator != usdeviceProperties.end()) + { + depth = depthIterator->second.ToString(); + } + else + { + depth = "0"; + } + + return depth; +} + +mitk::NavigationDataSource::Pointer mitk::AbstractUltrasoundTrackerDevice::RebuildFilterPipeline() +{ + itk::SmartPointer filter = m_TrackingDeviceDataSource; + + if( m_NumberOfSmoothingValues > 0 ) + { + for (unsigned int i = 0; i < m_TrackingDeviceDataSource->GetNumberOfOutputs(); i++) + { + m_SmoothingFilter->SetInput(i, filter->GetOutput(i)); + } + filter = m_SmoothingFilter; + } + + if( m_DelayCount > 0 ) + { + for( unsigned int i = 0; i < m_TrackingDeviceDataSource->GetNumberOfOutputs(); i++ ) + { + m_DelayFilter->SetInput(i, filter->GetOutput(i)); + } + filter = m_DelayFilter; + } + + return filter.GetPointer(); +} diff --git a/Modules/US/USNavigation/mitkUSCombinedModality.h b/Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.h similarity index 56% copy from Modules/US/USNavigation/mitkUSCombinedModality.h copy to Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.h index 4579e45e64..b485f003a9 100644 --- a/Modules/US/USNavigation/mitkUSCombinedModality.h +++ b/Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.h @@ -1,271 +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. ===================================================================*/ -#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 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 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 mitk::ImageSource + * \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; - mitkClassMacro(USCombinedModality, mitk::ImageSource); - mitkNewMacro4Param(USCombinedModality, USDevice::Pointer, itk::SmartPointer, std::string, std::string); + + mitkClassMacro(AbstractUltrasoundTrackerDevice, mitk::ImageSource); + mitkNewMacro3Param(AbstractUltrasoundTrackerDevice, USDevice::Pointer, itk::SmartPointer, bool); itkGetMacro(UltrasoundDevice, itk::SmartPointer); itkSetMacro(UltrasoundDevice, itk::SmartPointer); - itkGetMacro(TrackingDevice, itk::SmartPointer); - itkSetMacro(TrackingDevice, itk::SmartPointer); + itkGetMacro(TrackingDeviceDataSource, itk::SmartPointer); + itkSetMacro(TrackingDeviceDataSource, itk::SmartPointer); /** * \brief Getter for calibration data of the currently active depth and probe. * * \return Transformation for calibration or null if no calibration is available. */ AffineTransform3D::Pointer GetCalibration(); /** - * \brief Getter for calibration data of the given depth and the currently active probe. - * - * \param depth depth of the b mode ultrasound image for which the calibration should be returned - * \return Transformation for calibration or null if no calibration is available. - */ + * \brief Getter for calibration data of the given depth and the currently active probe. + * + * \param depth depth of the b mode ultrasound image for which the calibration should be returned + * \return Transformation for calibration or null if no calibration is available. + */ AffineTransform3D::Pointer GetCalibration(std::string depth); /** - * \brief Getter for calibration data of the given depth and probe. - * - * \param depth depth of the b mode ultrasound image for which the calibration should be returned - * \param probe probe of the ultrasound device for which the calibration should be returned - * \return Transformation for calibration or null if no calibration is available. - */ + * \brief Getter for calibration data of the given depth and probe. + * + * \param depth depth of the b mode ultrasound image for which the calibration should be returned + * \param probe probe of the ultrasound device for which the calibration should be returned + * \return Transformation for calibration or null if no calibration is available. + */ AffineTransform3D::Pointer GetCalibration(std::string depth, std::string probe); /** * \brief Sets a transformation as calibration data. * Calibration data is set for the currently activated probe and their current * zoom factor. It also marks the device as calibrated. */ void SetCalibration(AffineTransform3D::Pointer calibration); /** - * \brief Removes the calibration data of the currently active depth and probe. - * \return true on success, false if there was no calibration - */ + * \brief Removes the calibration data of the currently active depth and probe. + * \return true on success, false if there was no calibration + */ bool RemoveCalibration(); /** - * \brief Removes the calibration data of the given depth and the currently active probe. - * - * \param depth depth of the b mode ultrasound image for which the calibration should be removed - * \return true on success, false if there was no calibration - */ + * \brief Removes the calibration data of the given depth and the currently active probe. + * + * \param depth depth of the b mode ultrasound image for which the calibration should be removed + * \return true on success, false if there was no calibration + */ bool RemoveCalibration(std::string depth); /** - * \brief Removes the calibration data of the given depth and probe. - * - * \param depth depth of the b mode ultrasound image for which the calibration should be removed - * \param probe probe of the ultrasound device for which the calibration should be removed - * \return true on success, false if there was no calibration - */ + * \brief Removes the calibration data of the given depth and probe. + * + * \param depth depth of the b mode ultrasound image for which the calibration should be removed + * \param probe probe of the ultrasound device for which the calibration should be removed + * \return true on success, false if there was no calibration + */ bool RemoveCalibration(std::string depth, std::string probe); /** * \brief Returns the Class of the Device. */ - virtual std::string GetDeviceClass(); + std::string GetDeviceClass(); /** * \brief Wrapper for returning USImageSource of the UltrasoundDevice. */ - virtual USImageSource::Pointer GetUSImageSource(); - - /** - * \brief Wrapper for returning custom control interface of the UltrasoundDevice. - */ - virtual itk::SmartPointer GetControlInterfaceCustom(); + USImageSource::Pointer GetUSImageSource(); - /** - * \brief Wrapper for returning B mode control interface of the UltrasoundDevice. - */ - virtual itk::SmartPointer GetControlInterfaceBMode(); + itk::SmartPointer GetNavigationDataSource(); /** - * \brief Wrapper for returning probes control interface of the UltrasoundDevice. + * \return true if the device is calibrated for the currently selected probe with the current zoom level */ - virtual itk::SmartPointer GetControlInterfaceProbes(); - - /** - * \brief Wrapper for returning doppler control interface of the UltrasoundDevice. - */ - virtual itk::SmartPointer GetControlInterfaceDoppler(); - - virtual itk::SmartPointer GetNavigationDataSource(); - - /** - * \return true if the device is calibrated for the currently selected probe with the current zoom level - */ bool GetIsCalibratedForCurrentStatus(); /** - * \return true if a calibration was loaded for at least one probe and depth - */ - bool GetContainsAtLeastOneCalibration(); - - /** - * \brief Remove this device from the micro service. - * This method is public for mitk::USCombinedModality, because this devices - * can be completly removed. This is not possible for API devices, which - * should be available while their sub module is loaded. + * \return true if a calibration was loaded for at least one probe and depth */ - void UnregisterOnService(); + bool GetContainsAtLeastOneCalibration(); /** * \brief Serializes all contained calibrations into an xml fragment. * * The returned string contains one parent node named "calibrations" and several * subnodes, one for each calibration that is present. */ std::string SerializeCalibration(); /** * \brief Deserializes a string provided by a prior call to Serialize(). * If the bool flag is true, all prior calibrations will be deleted. * If the flag is set to false, prior calibrations will be retained, but overwritten * if one of equal name is present. * * \throws mitk::Exception if the given string could not be parsed correctly. */ void DeserializeCalibration(const std::string &xmlString, bool clearPreviousCalibrations = true); void SetNumberOfSmoothingValues(unsigned int numberOfSmoothingValues); void SetDelayCount(unsigned int delayCount); - void RegisterAsMicroservice(); - /** - *\brief These Constants are used in conjunction with Microservices + * \brief Remove this device from the micro service. + * This method is public for mitk::USCombinedModality, because this devices + * can be completly removed. This is not possible for API devices, which + * should be available while their sub module is loaded. */ - static const std::string US_INTERFACE_NAME; - static const std::string US_PROPKEY_DEVICENAME; - static const std::string US_PROPKEY_CLASS; - static const std::string US_PROPKEY_ID; - protected: - USCombinedModality(USDevice::Pointer usDevice, itk::SmartPointer trackingDevice, std::string manufacturer = "", std::string model = ""); - virtual ~USCombinedModality(); + //void UnregisterOnService(); + virtual void RegisterAsMicroservice(); /** - * \brief Initializes UltrasoundDevice. + * \brief Wrapper for returning custom control interface of the UltrasoundDevice. */ - virtual bool OnInitialization(); + virtual itk::SmartPointer GetControlInterfaceCustom(); /** - * \brief Connects UltrasoundDevice. + * \brief Wrapper for returning B mode control interface of the UltrasoundDevice. */ - virtual bool OnConnection(); + virtual itk::SmartPointer GetControlInterfaceBMode(); /** - * \brief Disconnects UltrasoundDevice. + * \brief Wrapper for returning probes control interface of the UltrasoundDevice. */ - virtual bool OnDisconnection(); + virtual itk::SmartPointer GetControlInterfaceProbes(); /** - * \brief Activates UltrasoundDevice. + * \brief Wrapper for returning doppler control interface of the UltrasoundDevice. */ - virtual bool OnActivation(); + virtual itk::SmartPointer GetControlInterfaceDoppler(); /** - * \brief Deactivates UltrasoundDevice. + *\brief These Constants are used in conjunction with Microservices */ - virtual bool OnDeactivation(); + /*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;*/ - /** - * \brief Freezes or unfreezes UltrasoundDevice. - */ - virtual void OnFreeze(bool); + protected: + AbstractUltrasoundTrackerDevice( USDevice::Pointer usDevice, + itk::SmartPointer trackingDevice, + bool trackedUltrasoundActive ); + virtual ~AbstractUltrasoundTrackerDevice(); + + itkGetMacro(IsTrackedUltrasoundActive, bool); /** * \brief Grabs the next frame from the input. + * Must be implemented by the derived class. * This method is called internally, whenever Update() is invoked by an Output. */ - void GenerateData() override; + virtual void GenerateData() override; std::string GetIdentifierForCurrentCalibration(); std::string GetIdentifierForCurrentProbe(); std::string GetCurrentDepthValue(); - void RebuildFilterPipeline(); + itk::SmartPointer RebuildFilterPipeline(); USDevice::Pointer m_UltrasoundDevice; - itk::SmartPointer m_TrackingDevice; + itk::SmartPointer m_TrackingDeviceDataSource; std::map m_Calibrations; itk::SmartPointer m_SmoothingFilter; itk::SmartPointer m_DelayFilter; - itk::SmartPointer m_LastFilter; unsigned int m_NumberOfSmoothingValues; unsigned int m_DelayCount; private: /** * \brief The device's ServiceRegistration object that allows to modify it's Microservice registraton details. */ - us::ServiceRegistration m_ServiceRegistration; + //us::ServiceRegistration m_ServiceRegistration; /** * \brief Properties of the device's Microservice. */ - us::ServiceProperties m_ServiceProperties; + //us::ServiceProperties m_ServiceProperties; + + bool m_IsTrackedUltrasoundActive; }; + } // namespace mitk -MITK_DECLARE_SERVICE_INTERFACE(mitk::USCombinedModality, "org.mitk.services.USCombinedModality") -#endif // MITKUSCombinedModality_H_HEADER_INCLUDED_ +//MITK_DECLARE_SERVICE_INTERFACE(mitk::AbstractUltrasoundTrackerDevice, "org.mitk.services.AbstractUltrasoundTrackerDevice") + +#endif diff --git a/Modules/US/USNavigation/mitkUSCombinedModality.cpp b/Modules/US/USNavigation/mitkUSCombinedModality.cpp index d7c3ea2ef1..3c239a9ce2 100644 --- a/Modules/US/USNavigation/mitkUSCombinedModality.cpp +++ b/Modules/US/USNavigation/mitkUSCombinedModality.cpp @@ -1,581 +1,295 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkUSCombinedModality.h" -//#include "mitkUSDevice.h" -#include "mitkNavigationDataSource.h" +//#include "mitkNavigationDataSource.h" #include "mitkImageReadAccessor.h" #include #include #include "mitkTrackingDeviceSource.h" // US Control Interfaces #include "mitkUSControlInterfaceProbes.h" #include "mitkUSControlInterfaceBMode.h" #include "mitkUSControlInterfaceDoppler.h" + +//___ //Microservices #include #include #include #include -#include - -//TempIncludes -#include - const std::string mitk::USCombinedModality::DeviceClassIdentifier = "org.mitk.modules.us.USCombinedModality"; const char* mitk::USCombinedModality::DefaultProbeIdentifier = "default"; const char* mitk::USCombinedModality::ProbeAndDepthSeperator = "_"; const std::string mitk::USCombinedModality::US_INTERFACE_NAME = "org.mitk.services.USCombinedModality"; const std::string mitk::USCombinedModality::US_PROPKEY_DEVICENAME = US_INTERFACE_NAME + ".devicename"; const std::string mitk::USCombinedModality::US_PROPKEY_CLASS = US_INTERFACE_NAME + ".class"; const std::string mitk::USCombinedModality::US_PROPKEY_ID = US_INTERFACE_NAME + ".id"; +//____ -mitk::USCombinedModality::USCombinedModality(USDevice::Pointer usDevice, NavigationDataSource::Pointer trackingDevice, std::string manufacturer, std::string model) - : 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 - m_UltrasoundDevice->SetSpawnAcquireThread(false); } mitk::USCombinedModality::~USCombinedModality() { if (m_ServiceRegistration != nullptr) - m_ServiceRegistration.Unregister(); - m_ServiceRegistration = 0; -} - -std::string mitk::USCombinedModality::GetDeviceClass() -{ - return DeviceClassIdentifier; -} - -mitk::USImageSource::Pointer mitk::USCombinedModality::GetUSImageSource() -{ - 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."; + m_ServiceRegistration.Unregister(); } - - return m_UltrasoundDevice->GetControlInterfaceBMode(); + m_ServiceRegistration = 0; } -mitk::USControlInterfaceProbes::Pointer mitk::USCombinedModality::GetControlInterfaceProbes() +void mitk::USCombinedModality::UnregisterOnService() { - if (m_UltrasoundDevice.IsNull()) + if (m_UltrasoundDevice->GetDeviceState() == USDevice::State_Activated) { - MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; - mitkThrow() << "UltrasoundDevice must not be null."; + m_UltrasoundDevice->Deactivate(); } - - return m_UltrasoundDevice->GetControlInterfaceProbes(); -} - -mitk::USControlInterfaceDoppler::Pointer mitk::USCombinedModality::GetControlInterfaceDoppler() -{ - if (m_UltrasoundDevice.IsNull()) + if (m_UltrasoundDevice->GetDeviceState() == USDevice::State_Connected) { - MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; - mitkThrow() << "UltrasoundDevice must not be null."; + m_UltrasoundDevice->Disconnect(); } - return m_UltrasoundDevice->GetControlInterfaceDoppler(); -} - -void mitk::USCombinedModality::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; } -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 0; } - - 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() +void mitk::USCombinedModality::RegisterAsMicroservice() { - 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; - } -} + //Get Context + us::ModuleContext* context = us::GetModuleContext(); -bool mitk::USCombinedModality::OnConnection() -{ - if (m_UltrasoundDevice.IsNull()) - { - MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; - mitkThrow() << "UltrasoundDevice must not be null."; - } + //Define ServiceProps + //us::ServiceProperties props; + mitk::UIDGenerator uidGen = + mitk::UIDGenerator("org.mitk.services.USCombinedModality", 16); + m_ServiceProperties[US_PROPKEY_ID] = uidGen.GetUID(); + m_ServiceProperties[US_PROPKEY_DEVICENAME] = m_UltrasoundDevice->GetName(); + m_ServiceProperties[US_PROPKEY_CLASS] = mitk::USCombinedModality::DeviceClassIdentifier; - // 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(); - } + m_ServiceRegistration = context->RegisterService(this, m_ServiceProperties); } -bool mitk::USCombinedModality::OnDisconnection() +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->Disconnect(); + return m_UltrasoundDevice->GetControlInterfaceCustom(); } -bool mitk::USCombinedModality::OnActivation() +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."; } - 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(); - } + return m_UltrasoundDevice->GetControlInterfaceBMode(); } -bool mitk::USCombinedModality::OnDeactivation() +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."; } - 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(); + return m_UltrasoundDevice->GetControlInterfaceProbes(); } -void mitk::USCombinedModality::OnFreeze(bool freeze) +mitk::USControlInterfaceDoppler::Pointer mitk::USCombinedModality::GetControlInterfaceDoppler() { - 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(); + return m_UltrasoundDevice->GetControlInterfaceDoppler(); } -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(); 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(); +//====================================================================================================================== +/** +bool mitk::USCombinedModality::OnInitialization() +{ +if (m_UltrasoundDevice.IsNull()) +{ +MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; +mitkThrow() << "UltrasoundDevice must not be null."; } -void mitk::USCombinedModality::DeserializeCalibration(const std::string& xmlString, bool clearPreviousCalibrations) +if (m_UltrasoundDevice->GetDeviceState() < mitk::USDevice::State_Initialized) { - // 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; - } +return m_UltrasoundDevice->Initialize(); } - -std::string mitk::USCombinedModality::GetIdentifierForCurrentCalibration() +else { - return this->GetIdentifierForCurrentProbe() - + mitk::USCombinedModality::ProbeAndDepthSeperator - + this->GetCurrentDepthValue(); +return true; +} } -std::string mitk::USCombinedModality::GetIdentifierForCurrentProbe() +bool mitk::USCombinedModality::OnConnection() { - us::ServiceProperties usdeviceProperties = m_UltrasoundDevice->GetServiceProperties(); - - us::ServiceProperties::const_iterator probeIt = usdeviceProperties.find( - mitk::USDevice::GetPropertyKeys().US_PROPKEY_PROBES_SELECTED); +if (m_UltrasoundDevice.IsNull()) +{ +MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; +mitkThrow() << "UltrasoundDevice must not be null."; +} - // get probe identifier from control interface for probes - std::string probeName = mitk::USCombinedModality::DefaultProbeIdentifier; - if (probeIt != usdeviceProperties.end()) - { - probeName = (probeIt->second).ToString(); - } +// 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(); +} +} - // make sure that there is no '/' which would cause problems for TinyXML - std::replace(probeName.begin(), probeName.end(), '/', '-'); +bool mitk::USCombinedModality::OnDisconnection() +{ +if (m_UltrasoundDevice.IsNull()) +{ +MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; +mitkThrow() << "UltrasoundDevice must not be null."; +} - return probeName; +return m_UltrasoundDevice->Disconnect(); } -std::string mitk::USCombinedModality::GetCurrentDepthValue() +bool mitk::USCombinedModality::OnActivation() { - us::ServiceProperties usdeviceProperties = m_UltrasoundDevice->GetServiceProperties(); +if (m_UltrasoundDevice.IsNull()) +{ +MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; +mitkThrow() << "UltrasoundDevice must not be null."; +} - // 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); +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(); - if (depthIterator != usdeviceProperties.end()) - { - depth = depthIterator->second.ToString(); - } - else - { - depth = "0"; - } +// 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(); +} +} - return depth; +bool mitk::USCombinedModality::OnDeactivation() +{ +if (m_UltrasoundDevice.IsNull()) +{ +MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; +mitkThrow() << "UltrasoundDevice must not be null."; } -void mitk::USCombinedModality::RebuildFilterPipeline() +mitk::TrackingDeviceSource::Pointer trackingDeviceSource = dynamic_cast(m_TrackingDevice.GetPointer()); +if (trackingDeviceSource.IsNull()) { - m_LastFilter = m_TrackingDevice; +MITK_WARN("USCombinedModality")("USDevice") << "Cannot stop tracking as TrackingDeviceSource is null."; +} +trackingDeviceSource->StopTracking(); - 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; - } +m_UltrasoundDevice->Deactivate(); - 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; - } +return m_UltrasoundDevice->GetIsConnected(); } -void mitk::USCombinedModality::RegisterAsMicroservice() +void mitk::USCombinedModality::OnFreeze(bool freeze) { - //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] = m_UltrasoundDevice->GetName(); - props[US_PROPKEY_CLASS] = this->GetDeviceClass(); - - m_ServiceProperties = props; +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(); } +} - m_ServiceRegistration = context->RegisterService(this, props); +if (m_UltrasoundDevice.IsNull()) +{ +MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; +mitkThrow() << "UltrasoundDevice must not be null."; +} +m_UltrasoundDevice->SetIsFreezed(freeze); } +*/ diff --git a/Modules/US/USNavigation/mitkUSCombinedModality.h b/Modules/US/USNavigation/mitkUSCombinedModality.h index 4579e45e64..a027f6b119 100644 --- a/Modules/US/USNavigation/mitkUSCombinedModality.h +++ b/Modules/US/USNavigation/mitkUSCombinedModality.h @@ -1,271 +1,148 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKUSCombinedModality_H_HEADER_INCLUDED_ #define MITKUSCombinedModality_H_HEADER_INCLUDED_ #include #include "mitkUSDevice.h" #include "mitkImageSource.h" +#include "mitkAbstractUltrasoundTrackerDevice.h" #include "mitkNavigationDataSource.h" // Microservices #include #include namespace itk { template class SmartPointer; } namespace mitk { - class NavigationDataSmoothingFilter; - class NavigationDataDelayFilter; class USControlInterfaceBMode; class USControlInterfaceProbes; class USControlInterfaceDoppler; /** * \brief Combination of USDevice and NavigationDataSource. * This class can be used as 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 mitk::ImageSource + class MITKUSNAVIGATION_EXPORT USCombinedModality : public mitk::AbstractUltrasoundTrackerDevice { 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, mitk::ImageSource); - mitkNewMacro4Param(USCombinedModality, USDevice::Pointer, itk::SmartPointer, std::string, std::string); - - 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); + void UnregisterOnService(); - /** - * \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); + void RegisterAsMicroservice() override; - /** - * \brief Returns the Class of the Device. - */ - virtual std::string GetDeviceClass(); + mitkClassMacro(USCombinedModality, mitk::AbstractUltrasoundTrackerDevice); + mitkNewMacro3Param(USCombinedModality, USDevice::Pointer, itk::SmartPointer, bool); - /** - * \brief Wrapper for returning USImageSource of the UltrasoundDevice. - */ - virtual USImageSource::Pointer GetUSImageSource(); /** * \brief Wrapper for returning custom control interface of the UltrasoundDevice. */ - virtual itk::SmartPointer GetControlInterfaceCustom(); + virtual itk::SmartPointer GetControlInterfaceCustom() override; /** * \brief Wrapper for returning B mode control interface of the UltrasoundDevice. */ - virtual itk::SmartPointer GetControlInterfaceBMode(); + virtual itk::SmartPointer GetControlInterfaceBMode() override; /** * \brief Wrapper for returning probes control interface of the UltrasoundDevice. */ - virtual itk::SmartPointer GetControlInterfaceProbes(); + virtual itk::SmartPointer GetControlInterfaceProbes() override; /** * \brief Wrapper for returning doppler control interface of the UltrasoundDevice. */ - virtual itk::SmartPointer GetControlInterfaceDoppler(); - - 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(); + virtual itk::SmartPointer GetControlInterfaceDoppler() override; - /** - * \brief Deserializes a string provided by a prior call to Serialize(). - * If the bool flag is true, all prior calibrations will be deleted. - * If the flag is set to false, prior calibrations will be retained, but overwritten - * if one of equal name is present. - * - * \throws mitk::Exception if the given string could not be parsed correctly. - */ - void DeserializeCalibration(const std::string &xmlString, bool clearPreviousCalibrations = true); - - void SetNumberOfSmoothingValues(unsigned int numberOfSmoothingValues); - - void SetDelayCount(unsigned int delayCount); - - void RegisterAsMicroservice(); - - /** - *\brief These Constants are used in conjunction with Microservices - */ - static const std::string US_INTERFACE_NAME; - static const std::string US_PROPKEY_DEVICENAME; - static const std::string US_PROPKEY_CLASS; - static const std::string US_PROPKEY_ID; protected: - USCombinedModality(USDevice::Pointer usDevice, itk::SmartPointer trackingDevice, std::string manufacturer = "", std::string model = ""); + USCombinedModality( USDevice::Pointer usDevice, + itk::SmartPointer trackingDevice, + bool trackedUltrasoundActive = false ); virtual ~USCombinedModality(); /** * \brief Initializes UltrasoundDevice. */ - virtual bool OnInitialization(); + //___virtual bool OnInitialization(); /** * \brief Connects UltrasoundDevice. */ - virtual bool OnConnection(); + //___virtual bool OnConnection(); /** * \brief Disconnects UltrasoundDevice. */ - virtual bool OnDisconnection(); + //___virtual bool OnDisconnection(); /** * \brief Activates UltrasoundDevice. */ - virtual bool OnActivation(); + //___virtual bool OnActivation(); /** * \brief Deactivates UltrasoundDevice. */ - virtual bool OnDeactivation(); + //___ virtual bool OnDeactivation(); /** * \brief Freezes or unfreezes UltrasoundDevice. */ - virtual void OnFreeze(bool); + //___virtual void OnFreeze(bool); + + /** * \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; + private: + /** + * \brief The device's ServiceRegistration object that allows to modify it's Microservice registraton details. + */ + us::ServiceRegistration m_ServiceRegistration; - unsigned int m_NumberOfSmoothingValues; - unsigned int m_DelayCount; - - private: - /** - * \brief The device's ServiceRegistration object that allows to modify it's Microservice registraton details. - */ - us::ServiceRegistration m_ServiceRegistration; - - /** - * \brief Properties of the device's Microservice. - */ - us::ServiceProperties m_ServiceProperties; + /** + * \brief Properties of the device's Microservice. + */ + us::ServiceProperties m_ServiceProperties; }; } // namespace mitk - MITK_DECLARE_SERVICE_INTERFACE(mitk::USCombinedModality, "org.mitk.services.USCombinedModality") #endif // MITKUSCombinedModality_H_HEADER_INCLUDED_ diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/IO/mitkUSNavigationCombinedModalityPersistence.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/IO/mitkUSNavigationCombinedModalityPersistence.cpp index c1f5cff604..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->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->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->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..fc6f856adc 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,208 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #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) { m_CombinedModality = combinedModality; 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."; 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..17520876ca 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" 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); /** * \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); /** * \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 915bb6f9a3..1f29219b9c 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::USDevice::GetPropertyKeys().US_PROPKEY_CLASS + "=" + mitk::USCombinedModality::DeviceClassIdentifier + "))"; + //std::string filterOnlyCombinedModalities = "(&(" + us::ServiceConstants::OBJECTCLASS() + "=" + "org.mitk.services.USCombinedModality)(" + mitk::USDevice::GetPropertyKeys().US_PROPKEY_CLASS + "=" + mitk::USCombinedModality::DeviceClassIdentifier + "))"; //std::string filter = "(&(" + us::ServiceConstants::OBJECTCLASS() + "=" + "org.mitk.services.UltrasoundDevice))"; ui->combinedModalityListWidget->Initialize(mitk::USCombinedModality::US_PROPKEY_DEVICENAME); 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(); 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->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(); if (combinedModality.IsNull()) { ui->calibrationLoadStateLabel->setText("Selected device is no USCombinedModality."); emit SignalNoLongerReadyForNextStep(); return; } if (filename.isEmpty()) { bool calibrated = this->UpdateCalibrationState(); if (!calibrated) { emit SignalNoLongerReadyForNextStep(); } return; } QFile file(filename); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { MITK_WARN << "Cannot open file '" << filename.toStdString() << "' for reading."; ui->calibrationLoadStateLabel->setText("Cannot open file '" + filename + "' for reading."); emit SignalNoLongerReadyForNextStep(); return; } QTextStream inStream(&file); m_LoadedCalibration = inStream.readAll().toStdString(); if (m_LoadedCalibration.empty()) { MITK_WARN << "Failed to load file. Unsupported format?"; ui->calibrationLoadStateLabel->setText("Failed to load file. Unsupported format?"); emit SignalNoLongerReadyForNextStep(); return; } try { combinedModality->DeserializeCalibration(m_LoadedCalibration); } catch (const mitk::Exception& /*exception*/) { MITK_WARN << "Failed to deserialize calibration. Unsuppoerted format?"; ui->calibrationLoadStateLabel->setText("Failed to deserialize calibration. Unsuppoerted format?"); emit SignalNoLongerReadyForNextStep(); return; } ui->calibrationLoadStateLabel->setText("Loaded calibration : " + filename); m_CombinedModality = combinedModality; emit SignalReadyForNextStep(); } void QmitkUSNavigationStepCombinedModality::OnCombinedModalityCreateNewButtonClicked() { this->SetCombinedModalityCreateWidgetEnabled(true); } void QmitkUSNavigationStepCombinedModality::OnCombinedModalityCreationExit() { this->SetCombinedModalityCreateWidgetEnabled(false); mitk::DataNode::Pointer usNode = mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))->GetDataStorage()//GetDataStorage ->GetNamedNode("US Viewing Stream - Image 0"); if (usNode.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews(//Reinit usNode->GetData()->GetTimeGeometry());//GetNode } else { mitkThrow()<< "No reinit possible"; } } void QmitkUSNavigationStepCombinedModality::OnCombinedModalityEditExit() { this->SetCombinedModalityEditWidgetEnabled(false); ui->combinedModalityEditWidget->SetCombinedModality(0); } void QmitkUSNavigationStepCombinedModality::OnDeleteButtonClicked() { mitk::USCombinedModality::Pointer combinedModality = this->GetSelectedCombinedModality(); 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(); if (combinedModality.IsNotNull()) { if (!combinedModality->GetUltrasoundDevice()->GetIsConnected()) { combinedModality->GetUltrasoundDevice()->Connect(); } if (!combinedModality->GetUltrasoundDevice()->GetIsActive()) { combinedModality->GetUltrasoundDevice()->Activate(); } } } void QmitkUSNavigationStepCombinedModality::OnDisconnectButtonClicked() { mitk::USCombinedModality::Pointer combinedModality = this->GetSelectedCombinedModality(); if (combinedModality.IsNotNull()) { 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(); if (combinedModality.IsNotNull()) { QApplication::setOverrideCursor(Qt::WaitCursor); // make sure that the combined modality is in connected state before using it 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->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() { // 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(); 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..4725191d28 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(); 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 b46e945c3a..1449cdcfee 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepMarkerIntervention.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepMarkerIntervention.cpp @@ -1,1017 +1,1017 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkUSNavigationStepMarkerIntervention.h" #include "ui_QmitkUSNavigationStepMarkerIntervention.h" #include "mitkBaseRenderer.h" #include "mitkContourModel.h" #include "mitkNeedleProjectionFilter.h" #include "mitkNodeDisplacementFilter.h" #include "mitkSurface.h" #include "mitkTextAnnotation2D.h" #include #include #include "../Filter/mitkUSNavigationTargetIntersectionFilter.h" #include "../Filter/mitkUSNavigationTargetOcclusionFilter.h" #include "../Filter/mitkUSNavigationTargetUpdateFilter.h" #include "../QmitkUSNavigationMarkerPlacement.h" #include "../Widgets/QmitkZoneProgressBar.h" #include "../mitkUSTargetPlacementQualityCalculator.h" #include "../Interactors/mitkUSPointMarkInteractor.h" #include "usModuleRegistry.h" #include "mitkLookupTable.h" #include "mitkLookupTableProperty.h" #include "mitkSurface.h" // VTK #include "vtkCellLocator.h" #include "vtkDataSet.h" #include "vtkDoubleArray.h" #include "vtkFloatArray.h" #include "vtkIdList.h" #include "vtkLinearTransform.h" #include "vtkLookupTable.h" #include "vtkMath.h" #include "vtkOBBTree.h" #include "vtkPointData.h" #include "vtkPointData.h" #include "vtkPolyData.h" #include "vtkSelectEnclosedPoints.h" #include "vtkSmartPointer.h" #include "vtkSphereSource.h" #include "vtkTransformPolyDataFilter.h" #include "vtkWarpScalar.h" QmitkUSNavigationStepMarkerIntervention::QmitkUSNavigationStepMarkerIntervention(QWidget *parent) : QmitkUSAbstractNavigationStep(parent), m_NumberOfTargets(0), m_PlannedTargetsNodes(), m_ReachedTargetsNodes(), m_TargetProgressBar(new QmitkZoneProgressBar(QString::fromStdString("Target: %1 mm"), 200, 0, this)), m_PlannedTargetProgressBar(nullptr), m_CurrentTargetIndex(0), m_CurrentTargetReached(false), m_ShowPlanningColors(false), m_PointMarkInteractor(mitk::USPointMarkInteractor::New()), m_TargetNode(nullptr), m_TargetColorLookupTableProperty(nullptr), m_TargetSurface(nullptr), m_NeedleProjectionFilter(mitk::NeedleProjectionFilter::New()), m_NodeDisplacementFilter(mitk::NodeDisplacementFilter::New()), m_TargetUpdateFilter(mitk::USNavigationTargetUpdateFilter::New()), m_TargetOcclusionFilter(mitk::USNavigationTargetOcclusionFilter::New()), m_TargetIntersectionFilter(mitk::USNavigationTargetIntersectionFilter::New()), m_PlacementQualityCalculator(mitk::USTargetPlacementQualityCalculator::New()), m_TargetStructureWarnOverlay(mitk::TextAnnotation2D::New()), m_ReferenceSensorName(), m_NeedleSensorName(), m_ReferenceSensorIndex(1), m_NeedleSensorIndex(0), m_ListenerTargetCoordinatesChanged(this, &QmitkUSNavigationStepMarkerIntervention::UpdateTargetCoordinates), ui(new Ui::QmitkUSNavigationStepMarkerIntervention) { m_ActiveTargetColor[0] = 1; m_ActiveTargetColor[1] = 1; m_ActiveTargetColor[2] = 0; m_InactiveTargetColor[0] = 1; m_InactiveTargetColor[1] = 1; m_InactiveTargetColor[2] = 0.5; m_ReachedTargetColor[0] = 0.6; m_ReachedTargetColor[1] = 1; m_ReachedTargetColor[2] = 0.6; ui->setupUi(this); connect(ui->freezeImageButton, SIGNAL(SignalFreezed(bool)), this, SLOT(OnFreeze(bool))); connect(ui->backToLastTargetButton, SIGNAL(clicked()), this, SLOT(OnBackToLastTargetClicked())); connect(ui->targetReachedButton, SIGNAL(clicked()), this, SLOT(OnTargetLeft())); connect(this, SIGNAL(TargetReached(int)), this, SLOT(OnTargetReached())); connect(this, SIGNAL(TargetLeft(int)), this, SLOT(OnTargetLeft())); connect(ui->riskStructuresRangeWidget, SIGNAL(SignalZoneViolated(const mitk::DataNode *, mitk::Point3D)), this, SLOT(OnRiskZoneViolated(const mitk::DataNode *, mitk::Point3D))); m_PointMarkInteractor->CoordinatesChangedEvent.AddListener(m_ListenerTargetCoordinatesChanged); this->GenerateTargetColorLookupTable(); m_TargetProgressBar->SetTextFormatInvalid("Target is not on Needle Path"); ui->targetStructuresRangeLayout->addWidget(m_TargetProgressBar); m_TargetUpdateFilter->SetScalarArrayIdentifier("USNavigation::ReachedTargetScores"); } QmitkUSNavigationStepMarkerIntervention::~QmitkUSNavigationStepMarkerIntervention() { mitk::DataStorage::Pointer dataStorage = this->GetDataStorage(false); if (dataStorage.IsNotNull()) { // remove the node for the needle path mitk::DataNode::Pointer node = this->GetNamedDerivedNode("Needle Path", QmitkUSAbstractNavigationStep::DATANAME_BASENODE); if (node.IsNotNull()) { dataStorage->Remove(node); } } delete ui; m_PointMarkInteractor->CoordinatesChangedEvent.RemoveListener(m_ListenerTargetCoordinatesChanged); } bool QmitkUSNavigationStepMarkerIntervention::OnStartStep() { m_NeedleProjectionFilter->SelectInput(m_NeedleSensorIndex); // create node for Needle Projection mitk::DataNode::Pointer node = this->GetNamedDerivedNodeAndCreate("Needle Path", QmitkUSAbstractNavigationStep::DATANAME_BASENODE); node->SetData(m_NeedleProjectionFilter->GetProjection()); node->SetBoolProperty("show contour", true); // initialize warning overlay (and do not display it, yet) m_TargetStructureWarnOverlay->SetText("Warning: Needle is Inside the Target Structure."); m_TargetStructureWarnOverlay->SetVisibility(false); // set position and font size for the text overlay mitk::Point2D overlayPosition; overlayPosition.SetElement(0, 10.0f); overlayPosition.SetElement(1, 10.0f); m_TargetStructureWarnOverlay->SetPosition2D(overlayPosition); m_TargetStructureWarnOverlay->SetFontSize(18); // overlay should be red mitk::Color color; color[0] = 1; color[1] = 0; color[2] = 0; m_TargetStructureWarnOverlay->SetColor(color); mitk::ManualPlacementAnnotationRenderer::AddAnnotation(m_TargetStructureWarnOverlay.GetPointer(), "stdmulti.widget4"); return true; } bool QmitkUSNavigationStepMarkerIntervention::OnStopStep() { mitk::DataStorage::Pointer dataStorage = this->GetDataStorage(); // remove all reached nodes from the data storage for (QVector>::iterator it = m_ReachedTargetsNodes.begin(); it != m_ReachedTargetsNodes.end(); ++it) { dataStorage->Remove(*it); } m_ReachedTargetsNodes.clear(); m_CurrentTargetIndex = 0; // reset button states ui->freezeImageButton->setEnabled(false); ui->backToLastTargetButton->setEnabled(false); ui->targetReachedButton->setEnabled(true); // make sure that it is unfreezed after stopping the step ui->freezeImageButton->Unfreeze(); // remove base node for reached targets from the data storage mitk::DataNode::Pointer reachedTargetsNode = this->GetNamedDerivedNode( QmitkUSAbstractNavigationStep::DATANAME_BASENODE, QmitkUSNavigationMarkerPlacement::DATANAME_REACHED_TARGETS); if (reachedTargetsNode.IsNotNull()) { dataStorage->Remove(reachedTargetsNode); } return true; } bool QmitkUSNavigationStepMarkerIntervention::OnFinishStep() { return true; } bool QmitkUSNavigationStepMarkerIntervention::OnActivateStep() { this->ClearZones(); // clear risk zones before adding new ones // get target node from data storage and make sure that it contains data m_TargetNode = this->GetNamedDerivedNode(QmitkUSNavigationMarkerPlacement::DATANAME_TARGETSURFACE, QmitkUSNavigationMarkerPlacement::DATANAME_TUMOUR); if (m_TargetNode.IsNull() || m_TargetNode->GetData() == 0) { mitkThrow() << "Target node (" << QmitkUSNavigationMarkerPlacement::DATANAME_TARGETSURFACE << ") must not be null."; } // get target data and make sure that it is a surface m_TargetSurface = dynamic_cast(m_TargetNode->GetData()); if (m_TargetSurface.IsNull()) { mitkThrow() << "Target node (" << QmitkUSNavigationMarkerPlacement::DATANAME_TARGETSURFACE << ") data must be of type mitk::Surface"; } // delete progress bars for reinitializing them again afterwards if (m_PlannedTargetProgressBar) { ui->targetStructuresRangeLayout->removeWidget(m_PlannedTargetProgressBar); delete m_PlannedTargetProgressBar; m_PlannedTargetProgressBar = 0; } m_NodeDisplacementFilter->SelectInput(m_ReferenceSensorIndex); this->UpdateTargetProgressDisplay(); mitk::DataNode::Pointer tumourNode = this->GetNamedDerivedNode(QmitkUSNavigationMarkerPlacement::DATANAME_TUMOUR, QmitkUSAbstractNavigationStep::DATANAME_BASENODE); if (tumourNode.IsNotNull()) { // do not show tumour node during intervention (target surface is shown) tumourNode->SetBoolProperty("visible", false); // add tumour as a risk structure ui->riskStructuresRangeWidget->AddZone(tumourNode); } // set target structure for target update filter m_TargetUpdateFilter->SetTargetStructure(m_TargetNode); m_TargetOcclusionFilter->SetTargetStructure(m_TargetNode); // set lookup table of tumour node m_TargetNode->SetProperty("LookupTable", m_TargetColorLookupTableProperty); // mitk::DataNode::Pointer targetsBaseNode = this->GetNamedDerivedNode(QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS, QmitkUSAbstractNavigationStep::DATANAME_BASENODE); mitk::DataStorage::SetOfObjects::ConstPointer plannedTargetNodes; if (targetsBaseNode.IsNotNull()) { plannedTargetNodes = this->GetDataStorage()->GetDerivations(targetsBaseNode); } if (plannedTargetNodes.IsNotNull() && plannedTargetNodes->Size() > 0) { for (mitk::DataStorage::SetOfObjects::ConstIterator it = plannedTargetNodes->Begin(); it != plannedTargetNodes->End(); ++it) { m_PlannedTargetsNodes.push_back(it->Value()); } m_PlannedTargetProgressBar = new QmitkZoneProgressBar(QString::fromStdString("Planned Target"), 200, 0); ui->targetStructuresRangeLayout->addWidget(m_PlannedTargetProgressBar); } // add progress bars for risk zone nodes mitk::DataNode::Pointer zonesBaseNode = this->GetNamedDerivedNode(QmitkUSNavigationMarkerPlacement::DATANAME_ZONES, QmitkUSAbstractNavigationStep::DATANAME_BASENODE); // only add progress bars if the base node for zones was created if (zonesBaseNode.IsNotNull()) { mitk::DataStorage::SetOfObjects::ConstPointer zoneNodes = this->GetDataStorage()->GetDerivations(zonesBaseNode); for (mitk::DataStorage::SetOfObjects::ConstIterator it = zoneNodes->Begin(); it != zoneNodes->End(); ++it) { ui->riskStructuresRangeWidget->AddZone(it->Value()); } m_TargetOcclusionFilter->SelectStartPositionInput(m_NeedleSensorIndex); m_TargetOcclusionFilter->SetObstacleStructures(zoneNodes); } return true; } bool QmitkUSNavigationStepMarkerIntervention::OnDeactivateStep() { ui->freezeImageButton->Unfreeze(); return true; } void QmitkUSNavigationStepMarkerIntervention::OnUpdate() { // get navigation data source and make sure that it is not null mitk::NavigationDataSource::Pointer navigationDataSource = this->GetCombinedModality()->GetNavigationDataSource(); if (navigationDataSource.IsNull()) { MITK_ERROR("QmitkUSAbstractNavigationStep") ("QmitkUSNavigationStepMarkerIntervention") << "Navigation Data Source of Combined Modality must not be null."; mitkThrow() << "Navigation Data Source of Combined Modality must not be null."; } ui->riskStructuresRangeWidget->UpdateDistancesToNeedlePosition(navigationDataSource->GetOutput(m_NeedleSensorIndex)); this->UpdateBodyMarkerStatus(navigationDataSource->GetOutput(m_ReferenceSensorIndex)); this->UpdateTargetColors(); this->UpdateTargetScore(); this->UpdateTargetViolationStatus(); } void QmitkUSNavigationStepMarkerIntervention::OnSettingsChanged(const itk::SmartPointer settingsNode) { if (settingsNode.IsNull()) { return; } int numberOfTargets; if (settingsNode->GetIntProperty("settings.number-of-targets", numberOfTargets)) { m_NumberOfTargets = numberOfTargets; m_TargetUpdateFilter->SetNumberOfTargets(numberOfTargets); m_PlacementQualityCalculator->SetOptimalAngle(m_TargetUpdateFilter->GetOptimalAngle()); } std::string referenceSensorName; if (settingsNode->GetStringProperty("settings.reference-name-selected", referenceSensorName)) { m_ReferenceSensorName = referenceSensorName; } std::string needleSensorName; if (settingsNode->GetStringProperty("settings.needle-name-selected", needleSensorName)) { m_NeedleSensorName = needleSensorName; } this->UpdateSensorsNames(); } QString QmitkUSNavigationStepMarkerIntervention::GetTitle() { return "Computer-assisted Intervention"; } bool QmitkUSNavigationStepMarkerIntervention::GetIsRestartable() { return true; } QmitkUSAbstractNavigationStep::FilterVector QmitkUSNavigationStepMarkerIntervention::GetFilter() { FilterVector filter; filter.push_back(m_NeedleProjectionFilter.GetPointer()); filter.push_back(m_NodeDisplacementFilter.GetPointer()); filter.push_back(m_TargetOcclusionFilter.GetPointer()); return filter; } void QmitkUSNavigationStepMarkerIntervention::OnSetCombinedModality() { - mitk::USCombinedModality::Pointer combinedModality = this->GetCombinedModality(false); + mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->GetCombinedModality(false); if (combinedModality.IsNotNull()) { mitk::AffineTransform3D::Pointer calibration = combinedModality->GetCalibration(); if (calibration.IsNotNull()) { m_NeedleProjectionFilter->SetTargetPlane(calibration); } } ui->freezeImageButton->SetCombinedModality(combinedModality, m_ReferenceSensorIndex); this->UpdateSensorsNames(); } void QmitkUSNavigationStepMarkerIntervention::OnTargetReached() { m_CurrentTargetReached = true; } void QmitkUSNavigationStepMarkerIntervention::OnTargetLeft() { m_CurrentTargetReached = false; m_CurrentTargetIndex++; if (m_CurrentTargetIndex >= 0 && static_cast(m_CurrentTargetIndex) >= m_NumberOfTargets) { ui->targetReachedButton->setDisabled(true); } ui->backToLastTargetButton->setEnabled(true); ui->freezeImageButton->setEnabled(true); this->UpdateTargetProgressDisplay(); if (m_ReachedTargetsNodes.size() < m_CurrentTargetIndex) { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetName( (QString("Target ") + QString("%1").arg(m_CurrentTargetIndex, 2, 10, QLatin1Char('0'))).toStdString()); this->GetDataStorage()->Add( node, this->GetNamedDerivedNodeAndCreate(QmitkUSNavigationMarkerPlacement::DATANAME_REACHED_TARGETS, QmitkUSAbstractNavigationStep::DATANAME_BASENODE)); m_ReachedTargetsNodes.push_back(node); } mitk::DataNode::Pointer node = m_ReachedTargetsNodes.at(m_CurrentTargetIndex - 1); mitk::Surface::Pointer zone = mitk::Surface::New(); // create a vtk sphere with given radius vtkSphereSource *vtkData = vtkSphereSource::New(); vtkData->SetRadius(5); vtkData->SetCenter(0, 0, 0); vtkData->Update(); zone->SetVtkPolyData(vtkData->GetOutput()); vtkData->Delete(); // set vtk sphere and origin to data node node->SetData(zone); node->GetData()->GetGeometry()->SetOrigin( this->GetCombinedModality()->GetNavigationDataSource()->GetOutput(m_NeedleSensorIndex)->GetPosition()); node->SetColor(0.2, 0.9, 0.2); this->UpdateTargetCoordinates(node); } void QmitkUSNavigationStepMarkerIntervention::OnBackToLastTargetClicked() { if (m_CurrentTargetIndex < 1) { MITK_WARN << "Cannot go back to last target as there is no last target."; return; } m_CurrentTargetIndex--; if (m_ReachedTargetsNodes.size() > m_CurrentTargetIndex) { this->GetDataStorage()->Remove(m_ReachedTargetsNodes.last()); MITK_INFO("QmitkUSAbstractNavigationStep") ("QmitkUSNavigationStepMarkerIntervention") << "Removed Target " << m_ReachedTargetsNodes.size(); m_ReachedTargetsNodes.pop_back(); } if (m_CurrentTargetIndex == 0) { ui->backToLastTargetButton->setDisabled(true); } if (m_CurrentTargetIndex >= 0 && static_cast(m_CurrentTargetIndex) < m_NumberOfTargets) { ui->targetReachedButton->setEnabled(true); } ui->freezeImageButton->setEnabled(false); ui->freezeImageButton->Unfreeze(); this->UpdateTargetProgressDisplay(); m_TargetUpdateFilter->RemovePositionOfTarget(m_CurrentTargetIndex); } void QmitkUSNavigationStepMarkerIntervention::OnFreeze(bool freezed) { if (freezed) { this->GetCombinedModality()->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()->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 9fcf1e64ab..a41c4db55a 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPlacementPlanning.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPlacementPlanning.cpp @@ -1,817 +1,817 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkUSNavigationStepPlacementPlanning.h" #include "ui_QmitkUSNavigationStepPlacementPlanning.h" #include "../Interactors/mitkUSPointMarkInteractor.h" #include "../mitkUSTargetPlacementQualityCalculator.h" #include "mitkNeedleProjectionFilter.h" #include "mitkNodeDisplacementFilter.h" #include "usModuleRegistry.h" #include "../Filter/mitkUSNavigationTargetIntersectionFilter.h" #include "../Filter/mitkUSNavigationTargetUpdateFilter.h" #include "../QmitkUSNavigationMarkerPlacement.h" #include "mitkLookupTableProperty.h" #include "mitkSurface.h" #include #include "mitkLayoutAnnotationRenderer.h" #include "mitkTextAnnotation3D.h" #include "vtkFloatArray.h" #include "vtkLookupTable.h" #include "vtkPointData.h" #include "vtkPolyData.h" #include "vtkSmartPointer.h" #include "vtkLineSource.h" #include "vtkSphereSource.h" #include "vtkCenterOfMass.h" #include "vtkLinearTransform.h" #include "vtkPoints.h" #include "vtkTransformPolyDataFilter.h" #include "vtkUnstructuredGrid.h" #include "vtkMath.h" QmitkUSNavigationStepPlacementPlanning::QmitkUSNavigationStepPlacementPlanning(QWidget *parent) : QmitkUSAbstractNavigationStep(parent), m_NumberOfTargets(0), m_CurrentTargetIndex(0), m_BodyMarkerValid(false), m_PointMarkInteractor(mitk::USPointMarkInteractor::New()), m_TargetUpdateFilter(mitk::USNavigationTargetUpdateFilter::New()), m_NodeDisplacementFilter(mitk::NodeDisplacementFilter::New()), m_NeedleProjectionFilter(mitk::NeedleProjectionFilter::New()), m_TargetIntersectionFilter(mitk::USNavigationTargetIntersectionFilter::New()), m_PlacementQualityCalculator(mitk::USTargetPlacementQualityCalculator::New()), m_ReferenceSensorIndex(1), m_NeedleSensorIndex(0), m_ListenerTargetCoordinatesChanged(this, &QmitkUSNavigationStepPlacementPlanning::UpdateTargetCoordinates), ui(new Ui::QmitkUSNavigationStepPlacementPlanning) { ui->setupUi(this); connect(ui->freezeImageButton, SIGNAL(SignalFreezed(bool)), this, SLOT(OnFreeze(bool))); m_TargetUpdateFilter->SetScalarArrayIdentifier("USNavigation::PlanningPlacement"); this->GenerateTargetColorLookupTable(); } QmitkUSNavigationStepPlacementPlanning::~QmitkUSNavigationStepPlacementPlanning() { delete ui; } bool QmitkUSNavigationStepPlacementPlanning::OnStartStep() { // create node for needle projection mitk::DataNode::Pointer node = this->GetNamedDerivedNodeAndCreate("Needle Path", QmitkUSAbstractNavigationStep::DATANAME_BASENODE); node->SetData(m_NeedleProjectionFilter->GetProjection()); node->SetBoolProperty("show contour", true); // make sure that the targets node exist in the data storage this->GetNamedDerivedNodeAndCreate(QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS, QmitkUSAbstractNavigationStep::DATANAME_BASENODE); this->GetNamedDerivedNodeAndCreate(QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS_PATHS, QmitkUSAbstractNavigationStep::DATANAME_BASENODE); // listen to event of point mark interactor m_PointMarkInteractor->CoordinatesChangedEvent.AddListener(m_ListenerTargetCoordinatesChanged); return true; } bool QmitkUSNavigationStepPlacementPlanning::OnStopStep() { // remove listener to event of point mark interactor m_PointMarkInteractor->CoordinatesChangedEvent.RemoveListener(m_ListenerTargetCoordinatesChanged); m_CurrentTargetIndex = 0; m_TargetUpdateFilter->Reset(); m_NodeDisplacementFilter->ResetNodes(); // remove the planned target nodes from the data storage mitk::DataStorage::Pointer dataStorage = this->GetDataStorage(); for (QVector>::iterator it = m_PlannedTargetNodes.begin(); it != m_PlannedTargetNodes.end(); ++it) { dataStorage->Remove(*it); } m_PlannedTargetNodes.clear(); // remove the planned target path nodes from the data storage for (QVector>::iterator it = m_PlannedNeedlePaths.begin(); it != m_PlannedNeedlePaths.end(); ++it) { dataStorage->Remove(*it); } m_PlannedNeedlePaths.clear(); // remove the targets node from the data storage mitk::DataNode::Pointer targetsNode = this->GetNamedDerivedNode(QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS, QmitkUSAbstractNavigationStep::DATANAME_BASENODE); if (targetsNode.IsNotNull()) { dataStorage->Remove(targetsNode); } // remove the target paths node from the data storage mitk::DataNode::Pointer targetPathsNode = this->GetNamedDerivedNode( QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS_PATHS, QmitkUSAbstractNavigationStep::DATANAME_BASENODE); if (targetPathsNode.IsNotNull()) { dataStorage->Remove(targetPathsNode); } // make sure that the image is no longer freezed after stopping ui->freezeImageButton->Unfreeze(); return true; } bool QmitkUSNavigationStepPlacementPlanning::OnRestartStep() { this->OnStopStep(); this->OnStartStep(); return true; } bool QmitkUSNavigationStepPlacementPlanning::OnFinishStep() { // create scalars showing the planned positions on the target surface if (!m_PlannedTargetNodes.isEmpty()) { mitk::USNavigationTargetUpdateFilter::Pointer planningSurfaceFilter = mitk::USNavigationTargetUpdateFilter::New(); planningSurfaceFilter->SetOptimalAngle(0); planningSurfaceFilter->SetScalarArrayIdentifier("USNavigation::PlanningScalars"); planningSurfaceFilter->SetUseMaximumScore(true); planningSurfaceFilter->SetTargetStructure(m_TargetNode); unsigned int n = 0; for (QVector>::iterator it = m_PlannedTargetNodes.begin(); it != m_PlannedTargetNodes.end(); ++it) { bool isSurfaceEmpty; if (((*it)->GetBoolProperty("surface_empty", isSurfaceEmpty)) && isSurfaceEmpty) { // remove node from data storage if it is not fully planned this->GetDataStorage()->Remove(*it); } else { // set origin to filter for coloring target surface (good // positions are positions near to the origin) planningSurfaceFilter->SetControlNode(n, *it); } n++; } } // make sure that the image is no longer freezed after finishing ui->freezeImageButton->Unfreeze(); return true; } bool QmitkUSNavigationStepPlacementPlanning::OnActivateStep() { emit SignalReadyForNextStep(); m_NodeDisplacementFilter->SelectInput(m_ReferenceSensorIndex); m_NeedleProjectionFilter->SelectInput(m_NeedleSensorIndex); if (m_PlannedTargetNodes.empty()) { m_CurrentTargetIndex = 0; } else { m_CurrentTargetIndex = m_PlannedTargetNodes.size() - 1; } m_TargetNode = this->GetNamedDerivedNode(QmitkUSNavigationMarkerPlacement::DATANAME_TARGETSURFACE, QmitkUSNavigationMarkerPlacement::DATANAME_TUMOUR); m_TargetNode->SetBoolProperty("visible", true); // set lookup table of tumour node m_TargetNode->SetProperty("LookupTable", m_TargetColorLookupTableProperty); m_TargetUpdateFilter->SetTargetStructure(m_TargetNode); for (QVector>::iterator it = m_PlannedTargetNodes.begin(); it != m_PlannedTargetNodes.end(); ++it) { (*it)->SetBoolProperty("visible", true); } this->UpdateTargetDescriptions(); // m_TargetUpdateFilter->UpdateTargetScores(); return true; } bool QmitkUSNavigationStepPlacementPlanning::OnDeactivateStep() { ui->freezeImageButton->Unfreeze(); return true; } void QmitkUSNavigationStepPlacementPlanning::OnUpdate() { this->UpdateTargetColors(); // get navigation data source and make sure that it is not null mitk::NavigationDataSource::Pointer navigationDataSource = this->GetCombinedModality()->GetNavigationDataSource(); if (navigationDataSource.IsNull()) { MITK_ERROR("QmitkUSAbstractNavigationStep") ("QmitkUSNavigationStepPunctuationIntervention") << "Navigation Data Source of Combined Modality must not be null."; mitkThrow() << "Navigation Data Source of Combined Modality must not be null."; } navigationDataSource->Update(); this->UpdateBodyMarkerStatus(navigationDataSource->GetOutput(m_ReferenceSensorIndex)); ui->freezeImageButton->setEnabled(m_BodyMarkerValid); mitk::PointSet::Pointer needleProjectionPointSet = m_NeedleProjectionFilter->GetProjection(); if (needleProjectionPointSet->GetSize() == 2) { m_TargetIntersectionFilter->SetTargetSurface(dynamic_cast(m_TargetNode->GetData())); m_TargetIntersectionFilter->SetLine(needleProjectionPointSet); m_TargetIntersectionFilter->CalculateIntersection(); if (m_TargetIntersectionFilter->GetIsIntersecting()) { // only enable button if body marker is in the tracking volume, too ui->placeTargetButton->setEnabled(m_BodyMarkerValid); ui->placeTargetButton->setToolTip(""); if (m_PlannedTargetNodes.size() == m_NumberOfTargets - 1) { mitk::PointSet::Pointer targetPointSet = mitk::PointSet::New(); mitk::PointSet::PointIdentifier n = 0; for (QVector>::iterator it = m_PlannedTargetNodes.begin(); it != m_PlannedTargetNodes.end(); ++it) { targetPointSet->InsertPoint(n++, (*it)->GetData()->GetGeometry()->GetOrigin()); } targetPointSet->InsertPoint(n, m_TargetIntersectionFilter->GetIntersectionPoint()); this->CalculatePlanningQuality(dynamic_cast(m_TargetNode->GetData()), targetPointSet); } } else { ui->placeTargetButton->setEnabled(false); ui->placeTargetButton->setToolTip( "Target cannot be placed as the needle path is not intersecting the target surface."); // no not show planning quality if not all nodes are planned for now // and there is no needle path intersection if (m_PlannedTargetNodes.size() < m_NumberOfTargets) { ui->angleDifferenceValue->setText(""); ui->centersOfMassValue->setText(""); } } } } void QmitkUSNavigationStepPlacementPlanning::OnSettingsChanged(const itk::SmartPointer settingsNode) { int numberOfTargets; if (settingsNode->GetIntProperty("settings.number-of-targets", numberOfTargets)) { m_NumberOfTargets = numberOfTargets; m_TargetUpdateFilter->SetNumberOfTargets(numberOfTargets); m_PlacementQualityCalculator->SetOptimalAngle(m_TargetUpdateFilter->GetOptimalAngle()); } std::string referenceSensorName; if (settingsNode->GetStringProperty("settings.reference-name-selected", referenceSensorName)) { m_ReferenceSensorName = referenceSensorName; } std::string needleSensorName; if (settingsNode->GetStringProperty("settings.needle-name-selected", needleSensorName)) { m_NeedleSensorName = needleSensorName; } this->UpdateSensorsNames(); } QString QmitkUSNavigationStepPlacementPlanning::GetTitle() { return "Placement Planning"; } QmitkUSAbstractNavigationStep::FilterVector QmitkUSNavigationStepPlacementPlanning::GetFilter() { FilterVector filterVector; filterVector.push_back(m_NodeDisplacementFilter.GetPointer()); filterVector.push_back(m_NeedleProjectionFilter.GetPointer()); return filterVector; } void QmitkUSNavigationStepPlacementPlanning::OnSetCombinedModality() { - mitk::USCombinedModality::Pointer combinedModality = this->GetCombinedModality(false); + mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->GetCombinedModality(false); if (combinedModality.IsNotNull()) { mitk::AffineTransform3D::Pointer calibration = combinedModality->GetCalibration(); if (calibration.IsNotNull()) { m_NeedleProjectionFilter->SetTargetPlane(calibration); } } ui->freezeImageButton->SetCombinedModality(combinedModality, m_ReferenceSensorIndex); this->UpdateSensorsNames(); } void QmitkUSNavigationStepPlacementPlanning::OnFreeze(bool freeze) { if (freeze) this->GetCombinedModality()->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()->GetUltrasoundDevice()->SetIsFreezed(false); } void QmitkUSNavigationStepPlacementPlanning::OnPlaceTargetButtonClicked() { this->CreateTargetNodesIfNecessary(); mitk::DataNode::Pointer currentNode = m_PlannedTargetNodes.at(m_CurrentTargetIndex); currentNode->SetData(this->CreateSphere(5)); currentNode->SetBoolProperty("surface_empty", false); mitk::PointSet::Pointer needleProjection = m_NeedleProjectionFilter->GetProjection(); m_TargetIntersectionFilter->SetTargetSurface(dynamic_cast(m_TargetNode->GetData())); m_TargetIntersectionFilter->SetLine(m_NeedleProjectionFilter->GetProjection()); m_TargetIntersectionFilter->CalculateIntersection(); mitk::Point3D intersectionPoint = m_TargetIntersectionFilter->GetIntersectionPoint(); currentNode->GetData()->GetGeometry()->SetOrigin(intersectionPoint); m_TargetUpdateFilter->SetControlNode(m_CurrentTargetIndex, currentNode); mitk::PointSet::Pointer plannedPath = mitk::PointSet::New(); m_PlannedNeedlePaths.at(m_CurrentTargetIndex)->SetData(plannedPath); plannedPath->SetPoint(0, needleProjection->GetPoint(0)); plannedPath->SetPoint(1, intersectionPoint); if (m_CurrentTargetIndex < m_NumberOfTargets - 1) { this->OnGoToNextTarget(); } else { this->UpdateTargetDescriptions(); } this->ReinitNodeDisplacementFilter(); MITK_INFO("QmitkUSAbstractNavigationStep") ("QmitkUSNavigationStepPlacementPlanning") << "Target " << m_CurrentTargetIndex + 1 << " planned at position " << intersectionPoint << "."; } void QmitkUSNavigationStepPlacementPlanning::OnGoToPreviousTarget() { if (m_CurrentTargetIndex < 1) { mitkThrow() << "Cannot go to previous target as current target is first target."; } m_CurrentTargetIndex--; this->UpdateTargetDescriptions(); } void QmitkUSNavigationStepPlacementPlanning::OnGoToNextTarget() { m_CurrentTargetIndex++; this->UpdateTargetDescriptions(); } void QmitkUSNavigationStepPlacementPlanning::OnRemoveCurrentTargetClicked() { if (m_CurrentTargetIndex >= m_PlannedTargetNodes.size()) { MITK_WARN << "Cannot remove current target as there aren't as much planned target nodes."; return; } this->GetDataStorage()->Remove(m_PlannedTargetNodes.at(m_CurrentTargetIndex)); m_PlannedTargetNodes.remove(m_CurrentTargetIndex); this->GetDataStorage()->Remove(m_PlannedNeedlePaths.at(m_CurrentTargetIndex)); m_PlannedNeedlePaths.remove(m_CurrentTargetIndex); this->ReinitNodeDisplacementFilter(); for (int n = 0; n < m_PlannedTargetNodes.size(); ++n) { // set name of the target node according to its new index m_PlannedTargetNodes.at(n)->SetName( QString("Target %1").arg(n + 1, m_NumberOfTargets / 10 + 1, 10, QLatin1Char('0')).toStdString()); m_PlannedNeedlePaths.at(n)->SetName( QString("Target Path %1").arg(n + 1, m_NumberOfTargets / 10 + 1, 10, QLatin1Char('0')).toStdString()); } m_TargetUpdateFilter->RemovePositionOfTarget(m_CurrentTargetIndex); m_CurrentTargetIndex = m_PlannedTargetNodes.size(); this->UpdateTargetDescriptions(); MITK_INFO("QmitkUSAbstractNavigationStep") ("QmitkUSNavigationStepPlacementPlanning") << "Planned target " << m_CurrentTargetIndex + 1 << " removed."; } void QmitkUSNavigationStepPlacementPlanning::CreateTargetNodesIfNecessary() { mitk::DataStorage::Pointer dataStorage = this->GetDataStorage(); while (m_PlannedTargetNodes.size() <= m_CurrentTargetIndex) { QString targetNumber = QString("%1").arg(m_PlannedTargetNodes.size() + 1, m_NumberOfTargets / 10 + 1, 10, QLatin1Char('0')); mitk::DataNode::Pointer targetNode = this->GetNamedDerivedNodeAndCreate( (QString("Target ") + targetNumber).toStdString().c_str(), QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS); targetNode->SetOpacity(0.5); targetNode->SetBoolProperty("surface_empty", true); targetNode->SetData(mitk::Surface::New()); m_PlannedTargetNodes.push_back(targetNode); mitk::DataNode::Pointer targetPathNode = this->GetNamedDerivedNodeAndCreate((QString("Target Path ") + targetNumber).toStdString().c_str(), QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS_PATHS); targetPathNode->SetOpacity(0.5); targetPathNode->SetColor(1, 1, 1); targetPathNode->SetColor(1, 1, 1, nullptr, "contourcolor"); targetPathNode->SetBoolProperty("show contour", true); m_PlannedNeedlePaths.push_back(targetPathNode); mitk::Surface::Pointer pathSurface = mitk::Surface::New(); targetPathNode->SetData(pathSurface); } } void QmitkUSNavigationStepPlacementPlanning::UpdateTargetCoordinates(mitk::DataNode *dataNode) { bool surfaceEmpty; if (dataNode->GetBoolProperty("surface_empty", surfaceEmpty) && surfaceEmpty) { mitk::Point3D origin = dataNode->GetData()->GetGeometry()->GetOrigin(); dataNode->SetData(this->CreateSphere(5)); dataNode->SetBoolProperty("surface_empty", false); dataNode->GetData()->GetGeometry()->SetOrigin(origin); } this->ReinitNodeDisplacementFilter(); mitk::BaseData *baseData = dataNode->GetData(); if (!baseData) { mitkThrow() << "Data of the data node must not be null."; } mitk::BaseGeometry::Pointer geometry = baseData->GetGeometry(); if (geometry.IsNull()) { mitkThrow() << "Geometry of the data node must not be null."; } m_TargetUpdateFilter->SetControlNode(m_CurrentTargetIndex, dataNode); MITK_INFO("QmitkUSAbstractNavigationStep") ("QmitkUSNavigationStepPlacementPlanning") << "Target " << m_CurrentTargetIndex + 1 << " planned at position " << geometry->GetOrigin() << "."; if (ui->freezeImageButton->isChecked()) { ui->freezeImageButton->Unfreeze(); if (m_CurrentTargetIndex < m_NumberOfTargets - 1) { this->OnGoToNextTarget(); } } this->UpdateTargetDescriptions(); } void QmitkUSNavigationStepPlacementPlanning::UpdateTargetColors() { if (m_TargetNode.IsNull()) { return; } m_TargetNode->SetColor(1, 1, 1); mitk::BaseData *targetNodeData = m_TargetNode->GetData(); if (targetNodeData == 0) { return; } mitk::Surface::Pointer targetNodeSurface = dynamic_cast(targetNodeData); vtkSmartPointer targetNodeSurfaceVtk = targetNodeSurface->GetVtkPolyData(); vtkFloatArray *targetScoreScalars = dynamic_cast( targetNodeSurface->GetVtkPolyData()->GetPointData()->GetScalars("USNavigation::PlanningPlacement")); if (!targetScoreScalars) { return; } unsigned int numberOfTupels = targetScoreScalars->GetNumberOfTuples(); vtkSmartPointer colors = vtkSmartPointer::New(); colors->SetNumberOfComponents(1); colors->SetNumberOfTuples(numberOfTupels); colors->SetName("Colors"); double markerScore; for (unsigned int n = 0; n < numberOfTupels; n++) { targetScoreScalars->GetTuple(n, &markerScore); colors->SetTuple(n, &markerScore); } if (numberOfTupels > 0) { targetNodeSurfaceVtk->GetPointData()->SetScalars(colors); targetNodeSurfaceVtk->GetPointData()->Update(); } } void QmitkUSNavigationStepPlacementPlanning::UpdateTargetDescriptions() { ui->previousButton->setEnabled(m_CurrentTargetIndex > 0); ui->nextButton->setEnabled(m_CurrentTargetIndex + 1 < m_PlannedTargetNodes.size()); ui->removeButton->setEnabled(m_PlannedTargetNodes.size() > 0); ui->currentTargetLabel->setText( QString("Planning Target %1 of %2").arg(m_CurrentTargetIndex + 1).arg(m_NumberOfTargets)); ui->removeButton->setEnabled(m_CurrentTargetIndex < m_PlannedTargetNodes.size()); this->CalculatePlanningQuality(); } void QmitkUSNavigationStepPlacementPlanning::GenerateTargetColorLookupTable() { vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetHueRange(0.0, 0.27); lookupTable->SetSaturationRange(1.0, 1.0); lookupTable->SetValueRange(1.0, 1.0); lookupTable->SetTableRange(0.0, 1.0); lookupTable->Build(); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetVtkLookupTable(lookupTable); m_TargetColorLookupTableProperty = mitk::LookupTableProperty::New(lut); } void QmitkUSNavigationStepPlacementPlanning::ReinitNodeDisplacementFilter() { m_NodeDisplacementFilter->ResetNodes(); for (QVector>::iterator it = m_PlannedTargetNodes.begin(); it != m_PlannedTargetNodes.end(); ++it) { if (it->IsNotNull() && (*it)->GetData() != 0) { m_NodeDisplacementFilter->AddNode(*it); } } for (QVector>::iterator it = m_PlannedNeedlePaths.begin(); it != m_PlannedNeedlePaths.end(); ++it) { if (it->IsNotNull() && (*it)->GetData() != 0) { m_NodeDisplacementFilter->AddNode(*it); } } } void QmitkUSNavigationStepPlacementPlanning::CalculatePlanningQuality() { if (m_PlannedTargetNodes.size() != m_NumberOfTargets) { ui->angleDifferenceLabel->setEnabled(false); ui->centersOfMassLabel->setEnabled(false); ui->allTargetsPlannedLabel->setEnabled(false); ui->angleDifferenceValue->setText(""); ui->centersOfMassValue->setText(""); return; } ui->angleDifferenceLabel->setEnabled(true); ui->centersOfMassLabel->setEnabled(true); ui->allTargetsPlannedLabel->setEnabled(true); mitk::PointSet::Pointer targetPointSet = mitk::PointSet::New(); mitk::PointSet::PointIdentifier n = 0; for (QVector>::iterator it = m_PlannedTargetNodes.begin(); it != m_PlannedTargetNodes.end(); ++it) { targetPointSet->InsertPoint(n++, (*it)->GetData()->GetGeometry()->GetOrigin()); } mitk::DataNode::Pointer planningQualityResult = this->CalculatePlanningQuality(dynamic_cast(m_TargetNode->GetData()), targetPointSet); emit SignalIntermediateResult(planningQualityResult); } mitk::DataNode::Pointer QmitkUSNavigationStepPlacementPlanning::CalculatePlanningQuality( mitk::Surface::Pointer targetSurface, mitk::PointSet::Pointer targetPoints) { if (targetSurface.IsNull()) { mitkThrow() << "Target surface must not be null."; } m_PlacementQualityCalculator->SetTargetSurface(targetSurface); m_PlacementQualityCalculator->SetTargetPoints(targetPoints); m_PlacementQualityCalculator->Update(); mitk::DataNode::Pointer planningQualityResult = mitk::DataNode::New(); planningQualityResult->SetName("PlanningQuality"); double centersOfMassDistance = m_PlacementQualityCalculator->GetCentersOfMassDistance(); ui->centersOfMassValue->setText(QString::number(centersOfMassDistance, 103, 2) + " mm"); planningQualityResult->SetFloatProperty("USNavigation::CentersOfMassDistance", centersOfMassDistance); if (m_PlannedTargetNodes.size() > 1) { double meanAnglesDifference = m_PlacementQualityCalculator->GetMeanAngleDifference(); ui->angleDifferenceValue->setText(QString::number(meanAnglesDifference, 103, 2) + QString::fromLatin1(" °")); planningQualityResult->SetFloatProperty("USNavigation::MeanAngleDifference", meanAnglesDifference); planningQualityResult->SetProperty( "USNavigation::AngleDifferences", mitk::GenericProperty::New(m_PlacementQualityCalculator->GetAngleDifferences())); } else { ui->angleDifferenceValue->setText("not valid for one point"); } return planningQualityResult; } itk::SmartPointer QmitkUSNavigationStepPlacementPlanning::CreateSphere(float) { mitk::Surface::Pointer surface = mitk::Surface::New(); // create a vtk sphere with fixed radius vtkSphereSource *vtkData = vtkSphereSource::New(); vtkData->SetRadius(5); vtkData->SetCenter(0, 0, 0); vtkData->Update(); surface->SetVtkPolyData(vtkData->GetOutput()); vtkData->Delete(); return surface; } void QmitkUSNavigationStepPlacementPlanning::UpdateBodyMarkerStatus(mitk::NavigationData::Pointer bodyMarker) { if (bodyMarker.IsNull()) { MITK_ERROR("QmitkUSAbstractNavigationStep") ("QmitkUSNavigationStepPunctuationIntervention") << "Current Navigation Data for body marker of Combined Modality must not be null."; mitkThrow() << "Current Navigation Data for body marker of Combined Modality must not be null."; } m_BodyMarkerValid = bodyMarker->IsDataValid(); // update body marker status label if (m_BodyMarkerValid) { ui->bodyMarkerTrackingStatusLabel->setStyleSheet( "background-color: #8bff8b; margin-right: 1em; margin-left: 1em; border: 1px solid grey"); ui->bodyMarkerTrackingStatusLabel->setText("Body marker is inside the tracking volume."); } else { ui->bodyMarkerTrackingStatusLabel->setStyleSheet( "background-color: #ff7878; margin-right: 1em; margin-left: 1em; border: 1px solid grey"); ui->bodyMarkerTrackingStatusLabel->setText("Body marker is not inside the tracking volume."); } } void QmitkUSNavigationStepPlacementPlanning::UpdateSensorsNames() { - mitk::USCombinedModality::Pointer combinedModality = this->GetCombinedModality(false); + mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->GetCombinedModality(false); if (combinedModality.IsNull()) { return; } mitk::NavigationDataSource::Pointer navigationDataSource = combinedModality->GetNavigationDataSource(); if (navigationDataSource.IsNull()) { return; } if (!m_NeedleSensorName.empty()) { try { m_NeedleSensorIndex = navigationDataSource->GetOutputIndex(m_NeedleSensorName); } catch (const std::exception &e) { MITK_WARN("QmitkUSAbstractNavigationStep") ("QmitkUSNavigationStepPlacementPlanning") << "Cannot get index for needle sensor name: " << e.what(); } } if (this->GetNavigationStepState() >= QmitkUSAbstractNavigationStep::State_Active) { m_NeedleProjectionFilter->SelectInput(m_NeedleSensorIndex); } if (!m_ReferenceSensorName.empty()) { try { m_ReferenceSensorIndex = navigationDataSource->GetOutputIndex(m_ReferenceSensorName); } catch (const std::exception &e) { MITK_WARN("QmitkUSAbstractNavigationStep") ("QmitkUSNavigationStepPlacementPlanning") << "Cannot get index for reference sensor name: " << e.what(); } } if (this->GetNavigationStepState() >= QmitkUSAbstractNavigationStep::State_Active) { m_NodeDisplacementFilter->SelectInput(m_ReferenceSensorIndex); } ui->freezeImageButton->SetCombinedModality(combinedModality, m_ReferenceSensorIndex); } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.cpp index 1fdbbb5ded..da8dcdb3db 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,283 @@ /*=================================================================== 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() { // 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."; } // update body marker this->UpdateBodyMarkerStatus(navigationDataSource->GetOutput(1)); // update critical structures this->UpdateCriticalStructures(navigationDataSource->GetOutput(0),m_NeedleProjectionFilter->GetProjection()); //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); 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 2eb7f6eb31..78de94e420 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepTumourSelection.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepTumourSelection.cpp @@ -1,428 +1,428 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkUSNavigationStepTumourSelection.h" #include "ui_QmitkUSNavigationStepTumourSelection.h" #include "usModuleRegistry.h" #include "mitkDataNode.h" #include "mitkSurface.h" #include "mitkUSCombinedModality.h" #include "../Interactors/mitkUSZonesInteractor.h" #include "mitkNodeDisplacementFilter.h" #include "QmitkUSNavigationStepCombinedModality.h" #include "../QmitkUSNavigationMarkerPlacement.h" #include "mitkIOUtil.h" #include "vtkSmartPointer.h" #include "vtkDoubleArray.h" #include "vtkPolyData.h" #include "vtkPointData.h" #include "vtkWarpScalar.h" QmitkUSNavigationStepTumourSelection::QmitkUSNavigationStepTumourSelection(QWidget* parent) : QmitkUSAbstractNavigationStep(parent), m_targetSelectionOptional(false), m_SecurityDistance(0), m_Interactor(mitk::USZonesInteractor::New()), m_NodeDisplacementFilter(mitk::NodeDisplacementFilter::New()), m_StateMachineFilename("USZoneInteractions.xml"), m_ReferenceSensorIndex(1), m_ListenerChangeNode(this, &QmitkUSNavigationStepTumourSelection::TumourNodeChanged), ui(new Ui::QmitkUSNavigationStepTumourSelection) { ui->setupUi(this); connect(ui->freezeImageButton, SIGNAL(SignalFreezed(bool)), this, SLOT(OnFreeze(bool))); connect(ui->tumourSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(OnTumourSizeChanged(int))); connect(ui->deleteTumourButton, SIGNAL(clicked()), this, SLOT(OnDeleteButtonClicked())); m_SphereColor = mitk::Color(); //default color: green m_SphereColor[0] = 0; m_SphereColor[1] = 255; m_SphereColor[2] = 0; } void QmitkUSNavigationStepTumourSelection::SetTumorColor(mitk::Color c) { m_SphereColor = c; } void QmitkUSNavigationStepTumourSelection::SetTargetSelectionOptional(bool t) { m_targetSelectionOptional = t; } QmitkUSNavigationStepTumourSelection::~QmitkUSNavigationStepTumourSelection() { delete ui; } bool QmitkUSNavigationStepTumourSelection::OnStartStep() { m_TumourNode = this->GetNamedDerivedNodeAndCreate( QmitkUSNavigationMarkerPlacement::DATANAME_TUMOUR, QmitkUSAbstractNavigationStep::DATANAME_BASENODE); m_TumourNode->SetColor(m_SphereColor[0], m_SphereColor[1], m_SphereColor[2]); // load state machine and event config for data interactor m_Interactor->LoadStateMachine(m_StateMachineFilename, us::ModuleRegistry::GetModule("MitkUS")); m_Interactor->SetEventConfig("globalConfig.xml"); this->GetDataStorage()->ChangedNodeEvent.AddListener(m_ListenerChangeNode); m_TargetSurfaceNode = this->GetNamedDerivedNodeAndCreate( QmitkUSNavigationMarkerPlacement::DATANAME_TARGETSURFACE, QmitkUSNavigationMarkerPlacement::DATANAME_TUMOUR); // do not show the surface until this is requested m_TargetSurfaceNode->SetBoolProperty("visible", false); // make sure that scalars will be renderer on the surface m_TargetSurfaceNode->SetBoolProperty("scalar visibility", true); m_TargetSurfaceNode->SetBoolProperty("color mode", true); m_TargetSurfaceNode->SetBoolProperty("Backface Culling", true); return true; } bool QmitkUSNavigationStepTumourSelection::OnStopStep() { // make sure that imaging isn't freezed anymore ui->freezeImageButton->Unfreeze(); m_NodeDisplacementFilter->ResetNodes(); mitk::DataStorage::Pointer dataStorage = this->GetDataStorage(false); if (dataStorage.IsNotNull()) { // remove target surface node from data storage, if available there if (m_TargetSurfaceNode.IsNotNull()) { dataStorage->Remove(m_TargetSurfaceNode); } dataStorage->ChangedNodeEvent.RemoveListener(m_ListenerChangeNode); dataStorage->Remove(m_TumourNode); m_TumourNode = 0; } MITK_INFO("QmitkUSAbstractNavigationStep")("QmitkUSNavigationStepTumourSelection") << "Removing tumour."; return true; } bool QmitkUSNavigationStepTumourSelection::OnRestartStep() { ui->tumourSizeExplanationLabel->setEnabled(false); ui->tumourSizeLabel->setEnabled(false); ui->tumourSizeSlider->setEnabled(false); ui->deleteTumourButton->setEnabled(false); ui->tumourSizeSlider->blockSignals(true); ui->tumourSizeSlider->setValue(0); ui->tumourSizeSlider->blockSignals(false); emit SignalNoLongerReadyForNextStep(); return QmitkUSAbstractNavigationStep::OnRestartStep(); } bool QmitkUSNavigationStepTumourSelection::OnFinishStep() { // make sure that the surface has the right extent (in case the // tumor size was changed since the initial surface creation) m_TargetSurfaceNode->SetData(this->CreateTargetSurface()); return true; } bool QmitkUSNavigationStepTumourSelection::OnActivateStep() { m_Interactor = mitk::USZonesInteractor::New(); m_Interactor->LoadStateMachine(m_StateMachineFilename, us::ModuleRegistry::GetModule("MitkUS")); m_Interactor->SetEventConfig("globalConfig.xml"); m_NodeDisplacementFilter->SelectInput(m_ReferenceSensorIndex); //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(); 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()->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()->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) { 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 0bc2ce259f..391f9d6639 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,269 @@ /*=================================================================== 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->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(); 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()->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()->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); } 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 96d9c9b546..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->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 7438066960..46c3a5a217 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationMarkerPlacement.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationMarkerPlacement.cpp @@ -1,875 +1,875 @@ /*=================================================================== 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 #include "IO/mitkUSNavigationExperimentLogging.h" #include "IO/mitkUSNavigationStepTimer.h" #include #include #include #include #include #include #include "QmitkRenderWindow.h" #include "QmitkStdMultiWidget.h" #include "QmitkStdMultiWidgetEditor.h" #include "mitkLayoutAnnotationRenderer.h" #include "mitkCameraController.h" // scene serialization #include #include #include #include #include const std::string QmitkUSNavigationMarkerPlacement::VIEW_ID = "org.mitk.views.usmarkerplacement"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TUMOUR = "Tumour"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TARGETSURFACE = "Target Surface"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_ZONES = "Zones"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS = "Targets"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS_PATHS = "Target Paths"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_REACHED_TARGETS = "Reached Targets"; QmitkUSNavigationMarkerPlacement::QmitkUSNavigationMarkerPlacement() : m_Parent(nullptr), m_NavigationSteps(), m_UpdateTimer(new QTimer(this)), m_ImageAndNavigationDataLoggingTimer(new QTimer(this)), m_StdMultiWidget(nullptr), m_CombinedModality(nullptr), m_ReinitAlreadyDone(false), m_IsExperimentRunning(false), m_CurrentApplicationName(), m_NavigationStepTimer(mitk::USNavigationStepTimer::New()), m_ExperimentLogging(mitk::USNavigationExperimentLogging::New()), m_IconRunning(QPixmap(":/USNavigation/record.png")), m_IconNotRunning(QPixmap(":/USNavigation/record-gray.png")), m_ResultsDirectory(), m_ExperimentName(), m_ExperimentResultsSubDirectory(), m_NavigationStepNames(), m_LoggingBackend(), m_USImageLoggingFilter(mitk::USImageLoggingFilter::New()), m_NavigationDataRecorder(mitk::NavigationDataRecorder::New()), m_TargetNodeDisplacementFilter(nullptr), m_AblationZonesDisplacementFilter(mitk::NodeDisplacementFilter::New()), m_AblationZonesVector(), m_NeedleIndex(0), m_MarkerIndex(1), m_SceneNumber(1), m_WarnOverlay(mitk::TextAnnotation2D::New()), m_NavigationDataSource(nullptr), m_CurrentStorage(nullptr), m_ListenerDeviceChanged(this, &QmitkUSNavigationMarkerPlacement::OnCombinedModalityPropertyChanged), ui(new Ui::QmitkUSNavigationMarkerPlacement ) { connect(m_UpdateTimer, SIGNAL(timeout()), this, SLOT(OnTimeout())); connect( m_ImageAndNavigationDataLoggingTimer, SIGNAL(timeout()), this, SLOT(OnImageAndNavigationDataLoggingTimeout())); // scale running (and not running) icon the specific height m_IconRunning = m_IconRunning.scaledToHeight(20, Qt::SmoothTransformation); m_IconNotRunning = m_IconNotRunning.scaledToHeight(20, Qt::SmoothTransformation); // set prefix for experiment logging (only keys with this prefix are taken // into consideration m_ExperimentLogging->SetKeyPrefix("USNavigation::"); m_UpdateTimer->start(33); // every 33 Milliseconds = 30 Frames/Second } QmitkUSNavigationMarkerPlacement::~QmitkUSNavigationMarkerPlacement() { // remove listener for ultrasound device changes if (m_CombinedModality.IsNotNull() && m_CombinedModality->GetUltrasoundDevice().IsNotNull()) { m_CombinedModality->GetUltrasoundDevice()->RemovePropertyChangedListener(m_ListenerDeviceChanged); } // remove listener for ultrasound device changes if (m_CombinedModality.IsNotNull() && m_CombinedModality->GetUltrasoundDevice().IsNotNull()) { m_CombinedModality->GetUltrasoundDevice()->RemovePropertyChangedListener(m_ListenerDeviceChanged); } delete ui; } void QmitkUSNavigationMarkerPlacement::OnChangeAblationZone(int id, int newSize) { if ((static_cast(m_AblationZonesVector.size()) < id) || (id < 0)) { return; } MITK_INFO << "Ablation Zone " << id << " changed, new size: " << newSize; // create a vtk sphere with given radius vtkSphereSource *vtkData = vtkSphereSource::New(); vtkData->SetRadius(newSize / 2); vtkData->SetCenter(0, 0, 0); vtkData->SetPhiResolution(20); vtkData->SetThetaResolution(20); vtkData->Update(); mitk::Surface::Pointer zoneSurface = dynamic_cast(m_AblationZonesVector.at(id)->GetData()); zoneSurface->SetVtkPolyData(vtkData->GetOutput()); vtkData->Delete(); } void QmitkUSNavigationMarkerPlacement::OnAddAblationZone(int size) { m_AblationZonesDisplacementFilter->SetInitialReferencePose( m_CombinedModality->GetNavigationDataSource()->GetOutput(m_MarkerIndex)); mitk::DataNode::Pointer NewAblationZone = mitk::DataNode::New(); mitk::Point3D origin = m_CombinedModality->GetNavigationDataSource()->GetOutput(m_NeedleIndex)->GetPosition(); MITK_INFO("USNavigationLogging") << "Ablation Zone Added, initial size: " << size << ", origin: " << origin; mitk::Surface::Pointer zone = mitk::Surface::New(); // create a vtk sphere with given radius vtkSphereSource *vtkData = vtkSphereSource::New(); vtkData->SetRadius(size / 2); vtkData->SetCenter(0, 0, 0); vtkData->SetPhiResolution(20); vtkData->SetThetaResolution(20); vtkData->Update(); zone->SetVtkPolyData(vtkData->GetOutput()); vtkData->Delete(); // set vtk sphere and origin to data node (origin must be set // again, because of the new sphere set as data) NewAblationZone->SetData(zone); NewAblationZone->GetData()->GetGeometry()->SetOrigin(origin); mitk::Color SphereColor = mitk::Color(); // default color SphereColor[0] = 102; SphereColor[1] = 0; SphereColor[2] = 204; NewAblationZone->SetColor(SphereColor); NewAblationZone->SetOpacity(0.3); // set name of zone std::stringstream name; name << "Ablation Zone" << m_AblationZonesVector.size(); NewAblationZone->SetName(name.str()); // add zone to filter m_AblationZonesDisplacementFilter->AddNode(NewAblationZone); m_AblationZonesVector.push_back(NewAblationZone); this->GetDataStorage()->Add(NewAblationZone); } void QmitkUSNavigationMarkerPlacement::CreateQtPartControl(QWidget *parent) { m_Parent = parent; ui->setupUi(parent); connect(ui->navigationProcessWidget, SIGNAL(SignalCombinedModalityChanged(itk::SmartPointer)), this, SLOT(OnCombinedModalityChanged(itk::SmartPointer))); connect(ui->navigationProcessWidget, SIGNAL(SignalSettingsChanged(itk::SmartPointer)), this, SLOT(OnSettingsChanged(itk::SmartPointer))); connect(ui->navigationProcessWidget, SIGNAL(SignalActiveNavigationStepChanged(int)), this, SLOT(OnActiveNavigationStepChanged(int))); connect(ui->navigationProcessWidget, SIGNAL(SignalActiveNavigationStepChangeRequested(int)), this, SLOT(OnNextNavigationStepInitialization(int))); connect(ui->startExperimentButton, SIGNAL(clicked()), this, SLOT(OnStartExperiment())); connect(ui->finishExperimentButton, SIGNAL(clicked()), this, SLOT(OnFinishExperiment())); connect(ui->m_enableNavigationLayout, SIGNAL(clicked()), this, SLOT(OnChangeLayoutClicked())); connect(ui->m_RenderWindowSelection, SIGNAL(valueChanged(int)), this, SLOT(OnRenderWindowSelection())); connect(ui->m_RefreshView, SIGNAL(clicked()), this, SLOT(OnRefreshView())); connect(ui->navigationProcessWidget, SIGNAL(SignalIntermediateResult(const itk::SmartPointer)), this, SLOT(OnIntermediateResultProduced(const itk::SmartPointer))); ui->navigationProcessWidget->SetDataStorage(this->GetDataStorage()); // indicate that no experiment is running at start ui->runningLabel->setPixmap(m_IconNotRunning); ui->navigationProcessWidget->SetSettingsWidget(new QmitkUSNavigationCombinedSettingsWidget(m_Parent)); } 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_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->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()); 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..d1d1092eda 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,216 @@ /*=================================================================== 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 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: /** * \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(); QWidget *m_Parent; QmitkUSNavigationProcessWidget::NavigationStepVector m_NavigationSteps; QTimer *m_UpdateTimer; QTimer *m_ImageAndNavigationDataLoggingTimer; QmitkStdMultiWidget *m_StdMultiWidget; - itk::SmartPointer m_CombinedModality; + itk::SmartPointer m_CombinedModality; 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; Ui::QmitkUSNavigationMarkerPlacement *ui; }; #endif // USNAVIGATIONMARKERPLACEMENT_H 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 5ba42c6fd0..8ae43921ec 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUltrasoundCalibration.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUltrasoundCalibration.cpp @@ -1,1140 +1,1140 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkUltrasoundCalibration.h" #include // Qt #include #include #include #include // MITK #include //#include #include #include #include #include #include #include "mitkIRenderingManager.h" // us #include //VTK #include #include #include #include #include #include #include "internal/org_mbi_gui_qt_usnavigation_Activator.h" //sleep headers #include #include const std::string QmitkUltrasoundCalibration::VIEW_ID = "org.mitk.views.ultrasoundcalibration"; QmitkUltrasoundCalibration::QmitkUltrasoundCalibration() : m_USDeviceChanged(this, &QmitkUltrasoundCalibration::OnUSDepthChanged) { ctkPluginContext* pluginContext = mitk::PluginActivator::GetContext(); if (pluginContext) { // to be notified about service event of an USDevice pluginContext->connectServiceListener(this, "OnDeciveServiceEvent", QString::fromStdString("(" + us::ServiceConstants::OBJECTCLASS() + "=" + us_service_interface_iid() + ")")); } } QmitkUltrasoundCalibration::~QmitkUltrasoundCalibration() { m_Controls.m_CombinedModalityManagerWidget->blockSignals(true); mitk::USCombinedModality::Pointer combinedModality; 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; 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; 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->GetUltrasoundDevice()->GetDeviceState() < mitk::USDevice::State_Connected) { m_CombinedModality->GetUltrasoundDevice()->Connect(); } if (m_CombinedModality->GetUltrasoundDevice()->GetDeviceState() < mitk::USDevice::State_Activated) { m_CombinedModality->GetUltrasoundDevice()->Activate(); } QApplication::restoreOverrideCursor(); this->SwitchFreeze(); // Todo: Maybe display this elsewhere this->ShowNeedlePath(); // Switch active tab to Calibration page m_Controls.m_ToolBox->setItemEnabled(1, true); m_Controls.m_ToolBox->setCurrentIndex(1); } void QmitkUltrasoundCalibration::OnStartPlusCalibration() { if (m_CombinedModality.IsNull()){ m_CombinedModality = m_Controls.m_CombinedModalityManagerWidget->GetSelectedCombinedModality(); if (m_CombinedModality.IsNull()) { return; } //something went wrong, there is no combined modality } //setup server to send UltrasoundImages to PLUS mitk::IGTLServer::Pointer m_USServer = mitk::IGTLServer::New(true); m_USServer->SetName("EchoTrack Image Source"); m_USServer->SetHostname("127.0.0.1"); m_USServer->SetPortNumber(18944); m_USMessageProvider = mitk::IGTLMessageProvider::New(); m_USMessageProvider->SetIGTLDevice(m_USServer); m_USMessageProvider->SetFPS(5); m_USImageToIGTLMessageFilter = mitk::ImageToIGTLMessageFilter::New(); m_USImageToIGTLMessageFilter->ConnectTo(m_CombinedModality->GetUltrasoundDevice()); m_USImageToIGTLMessageFilter->SetName("USImage Filter"); //setup server to send TrackingData to PLUS m_TrackingServer = mitk::IGTLServer::New(true); m_TrackingServer->SetName("EchoTrack Tracking Source"); m_TrackingServer->SetHostname("127.0.0.1"); m_TrackingServer->SetPortNumber(18945); m_TrackingMessageProvider = mitk::IGTLMessageProvider::New(); m_TrackingMessageProvider->SetIGTLDevice(m_TrackingServer); m_TrackingMessageProvider->SetFPS(5); m_TrackingToIGTLMessageFilter = mitk::NavigationDataToIGTLMessageFilter::New(); - m_TrackingToIGTLMessageFilter->ConnectTo(m_CombinedModality->GetTrackingDevice()); + m_TrackingToIGTLMessageFilter->ConnectTo(m_CombinedModality->GetTrackingDeviceDataSource()); m_TrackingToIGTLMessageFilter->SetName("Tracker Filter"); typedef itk::SimpleMemberCommand< QmitkUltrasoundCalibration > CurCommandType; CurCommandType::Pointer newConnectionCommand = CurCommandType::New(); newConnectionCommand->SetCallbackFunction( this, &QmitkUltrasoundCalibration::OnPlusConnected); this->m_NewConnectionObserverTag = this->m_TrackingServer->AddObserver( mitk::NewClientConnectionEvent(), newConnectionCommand); //Open connections of both servers if (m_USServer->OpenConnection()) { MITK_INFO << "US Server opened its connection successfully"; m_USServer->StartCommunication(); } else { MITK_INFO << "US Server could not open its connection"; } if (m_TrackingServer->OpenConnection()) { MITK_INFO << "Tracking Server opened its connection successfully"; m_TrackingServer->StartCommunication(); } else { MITK_INFO << "Tracking Server could not open its connection"; } if (m_USMessageProvider->IsCommunicating() && m_TrackingMessageProvider->IsCommunicating()) { m_Controls.m_StartPlusCalibrationButton->setEnabled(false); m_Controls.m_GetCalibrationFromPLUS->setEnabled(true); m_Controls.m_StartStreaming->setEnabled(false); m_Controls.m_SavePlusCalibration->setEnabled(false); m_Controls.m_SetupStatus->setStyleSheet("QLabel { color : green; }"); m_Controls.m_SetupStatus->setText("Setup successfull you can now connect PLUS"); } else { m_Controls.m_SetupStatus->setStyleSheet("QLabel { color : red; }"); m_Controls.m_SetupStatus->setText("Something went wrong. Please try again"); } } void QmitkUltrasoundCalibration::OnStopPlusCalibration() { //closing all server and clients when PlusCalibration is finished if (m_USMessageProvider.IsNotNull()) { if (m_USMessageProvider->IsStreaming()) { m_USMessageProvider->StopStreamingOfSource(m_USImageToIGTLMessageFilter); } } if (m_TrackingMessageProvider.IsNotNull()) { if (m_TrackingMessageProvider->IsStreaming()) { m_TrackingMessageProvider->StopStreamingOfSource(m_TrackingToIGTLMessageFilter); } } if (m_USServer.IsNotNull()) { m_USServer->CloseConnection(); } if (m_TrackingServer.IsNotNull()) { m_TrackingServer->CloseConnection(); } if (m_TransformClient.IsNotNull()) { m_TransformClient->CloseConnection(); } m_Controls.m_GotCalibrationLabel->setText(""); m_Controls.m_ConnectionStatus->setText(""); m_Controls.m_SetupStatus->setText(""); m_Controls.m_StartPlusCalibrationButton->setEnabled(true); m_StreamingTimer->stop(); delete m_StreamingTimer; } void QmitkUltrasoundCalibration::OnPlusConnected() { emit NewConnectionSignal(); } void QmitkUltrasoundCalibration::OnNewConnection() { m_Controls.m_StartStreaming->setEnabled(true); m_Controls.m_ConnectionStatus->setStyleSheet("QLabel { color : green; }"); m_Controls.m_ConnectionStatus->setText("Connection successfull you can now start streaming"); } void QmitkUltrasoundCalibration::OnStreamingTimerTimeout() { m_USMessageProvider->Update(); m_TrackingMessageProvider->Update(); } void QmitkUltrasoundCalibration::OnStartStreaming() { m_USMessageProvider->StartStreamingOfSource(m_USImageToIGTLMessageFilter, 5); m_TrackingMessageProvider->StartStreamingOfSource(m_TrackingToIGTLMessageFilter, 5); m_Controls.m_StartStreaming->setEnabled(false); m_Controls.m_ConnectionStatus->setText(""); m_StreamingTimer->start((1.0 / 5.0 * 1000.0)); } void QmitkUltrasoundCalibration::OnGetPlusCalibration() { m_TransformClient = mitk::IGTLClient::New(true); m_TransformClient->SetHostname("127.0.0.1"); m_TransformClient->SetPortNumber(18946); m_TransformDeviceSource = mitk::IGTLDeviceSource::New(); m_TransformDeviceSource->SetIGTLDevice(m_TransformClient); m_TransformDeviceSource->Connect(); if (m_TransformDeviceSource->IsConnected()) { MITK_INFO << "successfully connected"; m_TransformDeviceSource->StartCommunication(); if (m_TransformDeviceSource->IsCommunicating()) { MITK_INFO << "communication started"; mitk::IGTLMessage::Pointer receivedMessage; bool condition = false; igtl::Matrix4x4 transformPLUS; while (!(receivedMessage.IsNotNull() && receivedMessage->IsDataValid())) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); m_TransformDeviceSource->Update(); receivedMessage = m_TransformDeviceSource->GetOutput(); igtl::TransformMessage::Pointer msg = dynamic_cast(m_TransformDeviceSource->GetOutput()->GetMessage().GetPointer()); if (msg == nullptr || msg.IsNull()) { MITK_INFO << "Received message could not be casted to TransformMessage. Skipping.."; continue; } else { if (std::strcmp(msg->GetDeviceName(), "ImageToTracker") != 0) { MITK_INFO << "Was not Image to Tracker Transform. Skipping..."; continue; } else { msg->GetMatrix(transformPLUS); condition = true; break; } } } if (condition) { this->ProcessPlusCalibration(transformPLUS); } else { m_Controls.m_GotCalibrationLabel->setStyleSheet("QLabel { color : red; }"); m_Controls.m_GotCalibrationLabel->setText("Something went wrong. Please try again"); } } else { MITK_INFO << " no connection"; m_Controls.m_GotCalibrationLabel->setStyleSheet("QLabel { color : red; }"); m_Controls.m_GotCalibrationLabel->setText("Something went wrong. Please try again"); } } else { m_Controls.m_GotCalibrationLabel->setStyleSheet("QLabel { color : red; }"); m_Controls.m_GotCalibrationLabel->setText("Something went wrong. Please try again"); } } void QmitkUltrasoundCalibration::ProcessPlusCalibration(igtl::Matrix4x4& imageToTracker) { mitk::AffineTransform3D::Pointer imageToTrackerTransform = mitk::AffineTransform3D::New(); itk::Matrix rotationFloat = itk::Matrix(); itk::Vector translationFloat = itk::Vector(); rotationFloat[0][0] = imageToTracker[0][0]; rotationFloat[0][1] = imageToTracker[0][1]; rotationFloat[0][2] = imageToTracker[0][2]; rotationFloat[1][0] = imageToTracker[1][0]; rotationFloat[1][1] = imageToTracker[1][1]; rotationFloat[1][2] = imageToTracker[1][2]; rotationFloat[2][0] = imageToTracker[2][0]; rotationFloat[2][1] = imageToTracker[2][1]; rotationFloat[2][2] = imageToTracker[2][2]; translationFloat[0] = imageToTracker[0][3]; translationFloat[1] = imageToTracker[1][3]; translationFloat[2] = imageToTracker[2][3]; imageToTrackerTransform->SetTranslation(translationFloat); imageToTrackerTransform->SetMatrix(rotationFloat); m_CombinedModality->SetCalibration(imageToTrackerTransform); m_Controls.m_ToolBox->setItemEnabled(2, true); m_Controls.m_SavePlusCalibration->setEnabled(true); m_Controls.m_GotCalibrationLabel->setStyleSheet("QLabel { color : green; }"); m_Controls.m_GotCalibrationLabel->setText("Recieved Calibration from PLUS you can now save it"); } void QmitkUltrasoundCalibration::OnStopCalibrationProcess() { this->ClearTemporaryMembers(); m_Timer->stop(); this->GetDataStorage()->Remove(m_Node); m_Node = 0; this->GetDataStorage()->Remove(m_CalibNode); m_CalibNode = 0; this->GetDataStorage()->Remove(m_WorldNode); m_WorldNode = 0; m_Controls.m_ToolBox->setCurrentIndex(0); } void QmitkUltrasoundCalibration::OnDeciveServiceEvent(const ctkServiceEvent event) { if (m_CombinedModality.IsNull() || event.getType() != ctkServiceEvent::MODIFIED) { return; } ctkServiceReference service = event.getServiceReference(); QString curDepth = service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH)).toString(); if (m_CurrentDepth != curDepth) { m_CurrentDepth = curDepth; this->OnReset(); } } void QmitkUltrasoundCalibration::OnAddCalibPoint() { mitk::Point3D world = this->GetRenderWindowPart()->GetSelectedPosition(); this->m_CalibPointsImage->InsertPoint(m_CalibPointsCount, world); this->m_CalibPointsTool->InsertPoint(m_CalibPointsCount, this->m_FreezePoint); QString text = text.number(m_CalibPointsCount + 1); text = "Point " + text; this->m_Controls.m_CalibPointList->addItem(text); m_CalibPointsCount++; SwitchFreeze(); } void QmitkUltrasoundCalibration::OnCalibration() { // Compute transformation vtkSmartPointer transform = vtkSmartPointer::New(); transform->SetSourceLandmarks(this->ConvertPointSetToVtkPolyData(m_CalibPointsImage)->GetPoints()); transform->SetTargetLandmarks(this->ConvertPointSetToVtkPolyData(m_CalibPointsTool)->GetPoints()); if (m_Controls.m_ScaleTransform->isChecked()) { transform->SetModeToSimilarity(); } //use affine transform else { transform->SetModeToRigidBody(); } //use similarity transform: scaling is not touched transform->Modified(); transform->Update(); // Convert from vtk to itk data types itk::Matrix rotationFloat = itk::Matrix(); itk::Vector translationFloat = itk::Vector(); vtkSmartPointer m = transform->GetMatrix(); rotationFloat[0][0] = m->GetElement(0, 0); rotationFloat[0][1] = m->GetElement(0, 1); rotationFloat[0][2] = m->GetElement(0, 2); rotationFloat[1][0] = m->GetElement(1, 0); rotationFloat[1][1] = m->GetElement(1, 1); rotationFloat[1][2] = m->GetElement(1, 2); rotationFloat[2][0] = m->GetElement(2, 0); rotationFloat[2][1] = m->GetElement(2, 1); rotationFloat[2][2] = m->GetElement(2, 2); translationFloat[0] = m->GetElement(0, 3); translationFloat[1] = m->GetElement(1, 3); translationFloat[2] = m->GetElement(2, 3); mitk::DataNode::Pointer CalibPointsImage = mitk::DataNode::New(); CalibPointsImage->SetName("Calibration Points Image"); CalibPointsImage->SetData(m_CalibPointsImage); this->GetDataStorage()->Add(CalibPointsImage); mitk::DataNode::Pointer CalibPointsTracking = mitk::DataNode::New(); CalibPointsTracking->SetName("Calibration Points Tracking"); CalibPointsTracking->SetData(m_CalibPointsTool); this->GetDataStorage()->Add(CalibPointsTracking); mitk::PointSet::Pointer ImagePointsTransformed = m_CalibPointsImage->Clone(); this->ApplyTransformToPointSet(ImagePointsTransformed, transform); mitk::DataNode::Pointer CalibPointsImageTransformed = mitk::DataNode::New(); CalibPointsImageTransformed->SetName("Calibration Points Image (Transformed)"); CalibPointsImageTransformed->SetData(ImagePointsTransformed); this->GetDataStorage()->Add(CalibPointsImageTransformed); // Set output variable mitk::AffineTransform3D::Pointer oldUSImageTransform = m_Image->GetGeometry()->GetIndexToWorldTransform(); //including spacing! MITK_INFO << "Old US Image transform: " << oldUSImageTransform; mitk::AffineTransform3D::Pointer calibTransform = mitk::AffineTransform3D::New(); calibTransform->SetTranslation(translationFloat); calibTransform->SetMatrix(rotationFloat); MITK_INFO << "Calibration transform: " << calibTransform; m_Transformation = mitk::AffineTransform3D::New(); if (!m_Controls.m_ScaleTransform->isChecked()) { m_Transformation->Compose(oldUSImageTransform); } m_Transformation->Compose(calibTransform); MITK_INFO << "New combined transform: " << m_Transformation; mitk::SlicedGeometry3D::Pointer sliced3d = dynamic_cast (m_Node->GetData()->GetGeometry()); mitk::PlaneGeometry::Pointer plane = const_cast (sliced3d->GetPlaneGeometry(0)); plane->SetIndexToWorldTransform(m_Transformation); // Save to US-Device m_CombinedModality->SetCalibration(m_Transformation); m_Controls.m_ToolBox->setItemEnabled(2, true); // Save to NeedleProjectionFilter m_NeedleProjectionFilter->SetTargetPlane(m_Transformation); // Update Calibration FRE m_CalibrationStatistics = mitk::PointSetDifferenceStatisticsCalculator::New(); mitk::PointSet::Pointer p1 = this->m_CalibPointsTool->Clone(); // We use clones to calculate statistics to avoid concurrency Problems // Create point set with transformed image calibration points for // calculating the difference of image calibration and tool // calibration points in one geometry space mitk::PointSet::Pointer p2 = mitk::PointSet::New(); int n = 0; for (mitk::PointSet::PointsConstIterator it = m_CalibPointsImage->Begin(); it != m_CalibPointsImage->End(); ++it, ++n) { p2->InsertPoint(n, m_Transformation->TransformPoint(it->Value())); } m_CalibrationStatistics->SetPointSets(p1, p2); //QString text = text.number(m_CalibrationStatistics->GetRMS()); QString text = QString::number(ComputeFRE(m_CalibPointsImage, m_CalibPointsTool, transform)); MITK_INFO << "Calibration FRE: " << text.toStdString().c_str(); m_Controls.m_EvalLblCalibrationFRE->setText(text); m_Node->SetStringProperty("Calibration FRE", text.toStdString().c_str()); // Enable Button to save Calibration m_Controls.m_CalibBtnSaveCalibration->setEnabled(true); } void QmitkUltrasoundCalibration::OnAddEvalTargetPoint() { mitk::Point3D world = this->GetRenderWindowPart()->GetSelectedPosition(); this->m_EvalPointsImage->InsertPoint(m_EvalPointsImage->GetSize(), world); this->m_EvalPointsTool->InsertPoint(m_EvalPointsTool->GetSize(), this->m_FreezePoint); QString text = text.number(this->m_EvalPointsTool->GetSize()); this->m_Controls.m_EvalLblNumTargetPoints->setText(text); // Update FREs // Update Evaluation FRE, but only if it contains more than one point (will crash otherwise) if ((m_EvalPointsProjected->GetSize() > 1) && (m_EvalPointsTool->GetSize() > 1)) { m_EvaluationStatistics = mitk::PointSetDifferenceStatisticsCalculator::New(); m_ProjectionStatistics = mitk::PointSetDifferenceStatisticsCalculator::New(); mitk::PointSet::Pointer p1 = this->m_EvalPointsTool->Clone(); // We use clones to calculate statistics to avoid concurrency Problems mitk::PointSet::Pointer p2 = this->m_EvalPointsImage->Clone(); mitk::PointSet::Pointer p3 = this->m_EvalPointsProjected->Clone(); m_EvaluationStatistics->SetPointSets(p1, p2); m_ProjectionStatistics->SetPointSets(p1, p3); QString evalText = evalText.number(m_EvaluationStatistics->GetRMS()); QString projText = projText.number(m_ProjectionStatistics->GetRMS()); m_Controls.m_EvalLblEvaluationFRE->setText(evalText); m_Controls.m_EvalLblProjectionFRE->setText(projText); } SwitchFreeze(); } void QmitkUltrasoundCalibration::OnAddEvalProjectedPoint() { MITK_WARN << "Projection Evaluation may currently be inaccurate."; // TODO: Verify correct Evaluation. Is the Point that is added really current? mitk::Point3D projection = this->m_NeedleProjectionFilter->GetProjection()->GetPoint(1); m_EvalPointsProjected->InsertPoint(m_EvalPointsProjected->GetSize(), projection); QString text = text.number(this->m_EvalPointsProjected->GetSize()); this->m_Controls.m_EvalLblNumProjectionPoints->setText(text); } void QmitkUltrasoundCalibration::OnSaveEvaluation() { //Filename without suffix QString filename = m_Controls.m_EvalFilePath->text() + "//" + m_Controls.m_EvalFilePrefix->text(); MITK_WARN << "CANNOT SAVE, ABORTING!"; /* not working any more TODO! mitk::PointSetWriter::Pointer psWriter = mitk::PointSetWriter::New(); psWriter->SetInput(0, m_CalibPointsImage); psWriter->SetInput(1, m_CalibPointsTool); psWriter->SetInput(2, m_EvalPointsImage); psWriter->SetInput(3, m_EvalPointsTool); psWriter->SetInput(4, m_EvalPointsProjected); psWriter->SetFileName(filename.toStdString() + ".xml"); psWriter->Write(); */ // TODO: New writer for transformations must be implemented. /* mitk::TransformationFileWriter::Pointer tWriter = mitk::TransformationFileWriter::New(); tWriter->SetInput(0, m_CalibPointsImage); tWriter->SetInput(1, m_CalibPointsTool); tWriter->SetInput(2, m_EvalPointsImage); tWriter->SetInput(3, m_EvalPointsTool); tWriter->SetInput(4, m_EvalPointsProjected); tWriter->SetOutputFilename(filename.toStdString() + ".txt"); tWriter->DoWrite(this->m_Transformation); */ } void QmitkUltrasoundCalibration::OnSaveCalibration() { m_Controls.m_GotCalibrationLabel->setText(""); QString filename = QFileDialog::getSaveFileName(QApplication::activeWindow(), "Save Calibration", "", "Calibration files *.cal"); QFile file(filename); if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { MITK_WARN << "Cannot open file '" << filename.toStdString() << "' for writing."; return; } std::string calibrationSerialization = m_CombinedModality->SerializeCalibration(); QTextStream outStream(&file); outStream << QString::fromStdString(calibrationSerialization); //save additional information if (m_Controls.m_saveAdditionalCalibrationLog->isChecked()) { mitk::SceneIO::Pointer mySceneIO = mitk::SceneIO::New(); QString filenameScene = filename + "_mitkScene.mitk"; mitk::NodePredicateNot::Pointer isNotHelperObject = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true))); mitk::DataStorage::SetOfObjects::ConstPointer nodesToBeSaved = this->GetDataStorage()->GetSubset(isNotHelperObject); mySceneIO->SaveScene(nodesToBeSaved, this->GetDataStorage(), filenameScene.toStdString().c_str()); } } void QmitkUltrasoundCalibration::OnReset() { this->ClearTemporaryMembers(); if (m_Transformation.IsNull()) { m_Transformation = mitk::AffineTransform3D::New(); } m_Transformation->SetIdentity(); if (m_Node.IsNotNull() && (m_Node->GetData() != nullptr) && (m_Node->GetData()->GetGeometry() != nullptr)) { mitk::SlicedGeometry3D::Pointer sliced3d = dynamic_cast (m_Node->GetData()->GetGeometry()); mitk::PlaneGeometry::Pointer plane = const_cast (sliced3d->GetPlaneGeometry(0)); plane->SetIndexToWorldTransform(m_Transformation); } QString text1 = text1.number(this->m_EvalPointsTool->GetSize()); this->m_Controls.m_EvalLblNumTargetPoints->setText(text1); QString text2 = text2.number(this->m_EvalPointsProjected->GetSize()); this->m_Controls.m_EvalLblNumProjectionPoints->setText(text2); } void QmitkUltrasoundCalibration::Update() { //QList nodes = this->GetDataManagerSelection(); // if (nodes.empty()) return; // Update Tracking Data std::vector* datas = new std::vector(); datas->push_back(m_Tracker->GetOutput()); m_Controls.m_CalibTrackingStatus->SetNavigationDatas(datas); m_Controls.m_CalibTrackingStatus->Refresh(); m_Controls.m_EvalTrackingStatus->SetNavigationDatas(datas); m_Controls.m_EvalTrackingStatus->Refresh(); // Update US Image m_CombinedModality->Modified(); m_CombinedModality->Update(); mitk::Image::Pointer m_Image = m_CombinedModality->GetOutput(); if (m_Image.IsNotNull() && m_Image->IsInitialized()) { if (m_OverrideSpacing) { m_Image->GetGeometry()->SetSpacing(m_Spacing); } if (m_Image.IsNotNull() && m_Image->IsInitialized()) { m_Node->SetData(m_Image); } } // Update Needle Projection m_NeedleProjectionFilter->Update(); //only update 2d window because it is faster //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->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->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->GetUltrasoundDevice()->GetIsFreezed()) { //device was already frozen so we need to delete all Spacing points because they need to be collected all at once // no need to check if all four points are already collected, because if thats the case you can no longer click the Freeze Button m_SpacingPoints->Clear(); m_Controls.m_SpacingPointsList->clear(); m_SpacingPointsCount = 0; m_Controls.m_SpacingAddPoint->setEnabled(false); m_CombinedModality->GetUltrasoundDevice()->SetIsFreezed(false); } else { m_CombinedModality->GetUltrasoundDevice()->SetIsFreezed(true); m_Controls.m_SpacingAddPoint->setEnabled(true); } //SwitchFreeze(); } void QmitkUltrasoundCalibration::OnAddSpacingPoint() { mitk::Point3D point = this->GetRenderWindowPart()->GetSelectedPosition(); this->m_SpacingPoints->InsertPoint(m_SpacingPointsCount, point); QString text = text.number(m_SpacingPointsCount + 1); text = "Point " + text; this->m_Controls.m_SpacingPointsList->addItem(text); m_SpacingPointsCount++; if (m_SpacingPointsCount == 4) //now we have all 4 points needed { m_Controls.m_SpacingAddPoint->setEnabled(false); m_Controls.m_CalculateSpacing->setEnabled(true); m_Controls.m_SpacingBtnFreeze->setEnabled(false); } } void QmitkUltrasoundCalibration::OnCalculateSpacing() { mitk::Point3D horizontalOne = m_SpacingPoints->GetPoint(0); mitk::Point3D horizontalTwo = m_SpacingPoints->GetPoint(1); mitk::Point3D verticalOne = m_SpacingPoints->GetPoint(2); mitk::Point3D verticalTwo = m_SpacingPoints->GetPoint(3); //Get the distances between the points in the image double xDistance = horizontalOne.EuclideanDistanceTo(horizontalTwo); double yDistance = verticalOne.EuclideanDistanceTo(verticalTwo); //Calculate the spacing of the image and fill a vector with it double xSpacing = 30 / xDistance; double ySpacing = 20 / yDistance; m_Spacing[0] = xSpacing; m_Spacing[1] = ySpacing; m_Spacing[2] = 1; MITK_INFO << m_Spacing; //Make sure the new spacing is applied to the USVideoDeviceImages m_OverrideSpacing = true; //Now that the spacing is set clear all stuff and return to Calibration m_SpacingPoints->Clear(); m_Controls.m_SpacingPointsList->clear(); m_SpacingPointsCount = 0; m_CombinedModality->GetUltrasoundDevice()->SetIsFreezed(false); } void QmitkUltrasoundCalibration::OnUSDepthChanged(const std::string& key, const std::string&) { //whenever depth of USImage is changed the spacing should no longer be overwritten if (key == mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH) { m_OverrideSpacing = false; } } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUltrasoundCalibration.h b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUltrasoundCalibration.h index 7efae7c8ab..a073d54c19 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUltrasoundCalibration.h +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUltrasoundCalibration.h @@ -1,348 +1,348 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkUltrasoundCalibration_h #define QmitkUltrasoundCalibration_h #include #include //QT //#include //MITK #include #include #include #include #include #include // Microservices #include "ui_QmitkUltrasoundCalibrationControls.h" #include #include #include #include /*! \brief QmitkUltrasoundCalibration \warning This view provides a simple calibration process. \sa QmitkFunctionality \ingroup ${plugin_target}_internal */ class QmitkUltrasoundCalibration : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: QmitkUltrasoundCalibration(); ~QmitkUltrasoundCalibration(); static const std::string VIEW_ID; virtual void CreateQtPartControl(QWidget *parent); void OnUSDepthChanged(const std::string&, const std::string&); protected slots: /** * \brief Triggered, whenever the user switches Tabs * */ void OnTabSwitch(int index); /** * \brief Triggered, when the user has clicked "select Devices". * */ //void OnSelectDevice(mitk::USCombinedModality::Pointer); void OnDeviceSelected(); void OnDeviceDeselected(); /** * \brief Triggered, when the user clicks "Add Point" * */ void OnAddCalibPoint(); /** * \brief Triggered, when the user clicks "Calibrate" * */ void OnCalibration(); /** * \brief Triggered, when the user clicks "Add Target Points". * * Adds an image point and an tracking point to their respective evaluation pointsets */ void OnAddEvalTargetPoint(); /** * \brief Triggered, when the user clicks "Add Point". * * Adds a projected point to the projected point evaluation set. */ void OnAddEvalProjectedPoint(); /** * \brief Triggered when the user clicks "Save Results" in the Evaluation tab. */ void OnSaveEvaluation(); /** * \brief Triggered when the user clicks "Save Calibration" in the Calibration tab. */ void OnSaveCalibration(); /** * \brief Triggered when the user clicks "Run Next Round". Also used as a reset mechanism. */ void OnReset(); /** * \brief Triggered in regular intervals by a timer, when live view is enabled. * */ void Update(); /** * \brief Freezes or unfreezes the image. */ void SwitchFreeze(); /** * */ void OnStartCalibrationProcess(); /** *\brief Method to use the PLUS-Toolkoit for Calibration of EchoTrack */ void OnStartPlusCalibration(); void OnStopPlusCalibration(); /** *\ brief Starts the Streaming of USImage and Navigation Data when PLUS is connected */ void OnStartStreaming(); void OnNewConnection(); /** \*brief Get the Calibration from the PLUS-Toolkit once Calibration with fCal is done */ void OnGetPlusCalibration(); /** \*brief Convert the recieved igtl::Matrix into an mitk::AffineTransform3D which can be used to calibrate the CombinedModality */ void ProcessPlusCalibration(igtl::Matrix4x4& imageToTracker); void OnStreamingTimerTimeout(); /** * */ void OnStopCalibrationProcess(); void OnAddCurrentTipPositionToReferencePoints(); void OnStartVerification(); void OnAddCurrentTipPositionForVerification(); void OnDeciveServiceEvent(const ctkServiceEvent event); void OnFreezeClicked(); void OnAddSpacingPoint(); void OnCalculateSpacing(); signals: /** * \brief used for thread seperation, the worker thread must not call OnNewConnection directly. * QT signals are thread safe and separate the threads */ void NewConnectionSignal(); protected: virtual void SetFocus(); /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer source, const QList& nodes); Ui::QmitkUltrasoundCalibrationControls m_Controls; /** * \brief Internal function that activates display of the needle path. */ void ShowNeedlePath(); /** * \brief Clears all member attributes which are holding intermediate results for the calibration. */ void ClearTemporaryMembers(); void OnPlusConnected(); /** * \brief The combined modality used for imaging and tracking. */ - mitk::USCombinedModality::Pointer m_CombinedModality; + mitk::AbstractUltrasoundTrackerDevice::Pointer m_CombinedModality; /** * \brief NavigationDataSource used for tracking data. * This will be gotten by the combined modality. */ mitk::NavigationDataSource::Pointer m_Tracker; QTimer *m_Timer; mitk::DataNode::Pointer m_Node; mitk::DataNode::Pointer m_CalibNode; mitk::DataNode::Pointer m_WorldNode; //IGTL Servers and Devices needed for the communication with PLUS mitk::IGTLServer::Pointer m_USServer; mitk::IGTLMessageProvider::Pointer m_USMessageProvider; mitk::ImageToIGTLMessageFilter::Pointer m_USImageToIGTLMessageFilter; mitk::IGTLServer::Pointer m_TrackingServer; mitk::IGTLMessageProvider::Pointer m_TrackingMessageProvider; mitk::NavigationDataToIGTLMessageFilter::Pointer m_TrackingToIGTLMessageFilter; mitk::IGTLClient::Pointer m_TransformClient; mitk::IGTLDeviceSource::Pointer m_TransformDeviceSource; QTimer *m_StreamingTimer; unsigned long m_NewConnectionObserverTag; // Variables to determine if spacing was calibrated and needs to be applied to the incoming images mitk::Vector3D m_Spacing; bool m_OverrideSpacing; /** * \brief The current Ultrasound Image. */ mitk::Image::Pointer m_Image; /** * \brief Current point when the image was last frozen. */ mitk::Point3D m_FreezePoint; /** * \brief Pointset containing all tool points. */ mitk::PointSet::Pointer m_CalibPointsImage; /** * \brief Pointset containing corresponding points on the image. */ mitk::PointSet::Pointer m_CalibPointsTool; /** * \brief Pointset containing Projected Points (aka "where we thought the needle was gonna land") */ mitk::PointSet::Pointer m_EvalPointsProjected; /** * \brief Pointset containing the evaluated points on the image. */ mitk::PointSet::Pointer m_EvalPointsImage; /** * \brief Pointset containing tracked evaluation points. */ mitk::PointSet::Pointer m_EvalPointsTool; /** * \brief Pointset containing tracked evaluation points. */ mitk::PointSet::Pointer m_VerificationReferencePoints; mitk::DataNode::Pointer m_VerificationReferencePointsDataNode; int m_currentPoint; std::vector m_allReferencePoints; std::vector m_allErrors; /** * \brief Pointset containing points along the needle's prohected path. Only used for visualization. The first point is the needle tip. */ //mitk::PointSet::Pointer m_NeedlePathPoints; /** * \brief Creates a Pointset that projects the needle's path */ mitk::NeedleProjectionFilter::Pointer m_NeedleProjectionFilter; /** * \brief Total number of calibration points set. */ int m_CalibPointsCount; QString m_CurrentDepth; /** * \brief StatisticsRegarding Projection Accuracy. * (Compares m_EvalPointsProjected to m_EvalPointsImage) */ mitk::PointSetDifferenceStatisticsCalculator::Pointer m_ProjectionStatistics; /** * \brief StatisticsRegarding Evaluation Accuracy. * (Compares m_EvalPointsTool to m_EvalPointsImage) */ mitk::PointSetDifferenceStatisticsCalculator::Pointer m_EvaluationStatistics; /** * \brief StatisticsRegarding Calibration Accuracy. * (Compares m_CalibPointsTool to a transformed copy of m_CalibPointsImage). */ mitk::PointSetDifferenceStatisticsCalculator::Pointer m_CalibrationStatistics; /** * \brief Result of the Calibration. */ mitk::AffineTransform3D::Pointer m_Transformation; /** * This method is copied from PointSetModifier which is part of MBI. It should be replaced * by external method call as soon as this functionality will be available in MITK. */ vtkSmartPointer ConvertPointSetToVtkPolyData(mitk::PointSet::Pointer PointSet); double ComputeFRE(mitk::PointSet::Pointer imageFiducials, mitk::PointSet::Pointer realWorldFiducials, vtkSmartPointer transform = nullptr); void ApplyTransformToPointSet(mitk::PointSet::Pointer pointSet, vtkSmartPointer transform); mitk::PointSet::Pointer m_SpacingPoints; mitk::DataNode::Pointer m_SpacingNode; int m_SpacingPointsCount; private: mitk::MessageDelegate2 m_USDeviceChanged; }; #endif // UltrasoundCalibration_h diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityCreationWidget.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityCreationWidget.cpp index e9d0e1c9f8..19b7efb0f3 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityCreationWidget.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityCreationWidget.cpp @@ -1,81 +1,81 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkUSCombinedModalityCreationWidget.h" #include "ui_QmitkUSCombinedModalityCreationWidget.h" QmitkUSCombinedModalityCreationWidget::QmitkUSCombinedModalityCreationWidget(QWidget *parent) : QWidget(parent), ui(new Ui::QmitkUSCombinedModalityCreationWidget) { ui->setupUi(this); std::string filterExcludeCombinedModalities = "(&(" + us::ServiceConstants::OBJECTCLASS() + "=" + "org.mitk.services.UltrasoundDevice)(!(" + mitk::USDevice::GetPropertyKeys().US_PROPKEY_CLASS + "=" + mitk::USCombinedModality::DeviceClassIdentifier + ")))"; connect(ui->usDevicesServiceList, SIGNAL(ServiceSelectionChanged(us::ServiceReferenceU)), this, SLOT(OnSelectedUltrasoundOrTrackingDevice())); connect(ui->trackingDevicesServiceList, SIGNAL(ServiceSelectionChanged(us::ServiceReferenceU)), this, SLOT(OnSelectedUltrasoundOrTrackingDevice())); ui->usDevicesServiceList->SetAutomaticallySelectFirstEntry(true); ui->trackingDevicesServiceList->SetAutomaticallySelectFirstEntry(true); ui->usDevicesServiceList->Initialize(mitk::USDevice::GetPropertyKeys().US_PROPKEY_LABEL, filterExcludeCombinedModalities); ui->trackingDevicesServiceList->Initialize(mitk::NavigationDataSource::US_PROPKEY_DEVICENAME); connect(ui->createButton, SIGNAL(clicked()), this, SLOT(OnCreation())); connect(ui->cancelButton, SIGNAL(clicked()), this, SIGNAL(SignalAborted())); } QmitkUSCombinedModalityCreationWidget::~QmitkUSCombinedModalityCreationWidget() { delete ui; } void QmitkUSCombinedModalityCreationWidget::OnCreation() { mitk::USDevice::Pointer usDevice = ui->usDevicesServiceList->GetSelectedService(); if (usDevice.IsNull()) { MITK_WARN << "No Ultrasound Device selected for creation of Combined Modality."; return; } mitk::NavigationDataSource::Pointer trackingDevice = ui->trackingDevicesServiceList->GetSelectedService(); if (trackingDevice.IsNull()) { MITK_WARN << "No Traccking Device selected for creation of Combined Modality."; return; } QString vendor = ui->vendorLineEdit->text(); QString name = ui->nameLineEdit->text(); if (name.isEmpty()) { name = "Combined Modality"; } - mitk::USCombinedModality::Pointer combinedModality = mitk::USCombinedModality::New( - usDevice, trackingDevice, vendor.toStdString(), name.toStdString()); - combinedModality->GetUltrasoundDevice()->Initialize(); - combinedModality->RegisterAsMicroservice(); // register as micro service + m_CombinedModality = mitk::USCombinedModality::New(usDevice, trackingDevice, false); + + m_CombinedModality->GetUltrasoundDevice()->Initialize(); + m_CombinedModality->RegisterAsMicroservice(); // register as micro service emit SignalCreated(); - emit SignalCreated(combinedModality); + //emit SignalCreated(m_CombinedModality); } void QmitkUSCombinedModalityCreationWidget::OnSelectedUltrasoundOrTrackingDevice() { // create button is enabled only if an ultrasound // and a tracking device is selected ui->createButton->setEnabled( ui->usDevicesServiceList->GetIsServiceSelected() && ui->trackingDevicesServiceList->GetIsServiceSelected()); } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityCreationWidget.h b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityCreationWidget.h index f98b4f8e65..1b43d5ea25 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityCreationWidget.h +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityCreationWidget.h @@ -1,62 +1,64 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKUSCOMBINEDMODALITYCREATIONWIDGET_H #define QMITKUSCOMBINEDMODALITYCREATIONWIDGET_H #include #include "mitkUSCombinedModality.h" namespace Ui { class QmitkUSCombinedModalityCreationWidget; } /** * \brief Widget that enables the user to create a mitk::USCombinedModality of a mitk::NavigationDataSource and a mitk::USDevice. * A mitk::NavigationDataSource and a mitk::USDevice can be picked from two lists, showing * the corresponding micro service objects. The combined modality is registered as a micro * service as well during the creation process. */ class QmitkUSCombinedModalityCreationWidget : public QWidget { Q_OBJECT signals: /** \brief Emmited when the user clicks the "Cancel" button. */ void SignalAborted(); /** \brief Emmited when the user clicked the "Create" button and the creation is successfull. */ void SignalCreated(mitk::USCombinedModality::Pointer combinedModality); /** \brief Emmited when the user clicked the "Create" button and the creation is successfull. */ void SignalCreated(); protected slots: /** \brief Creates a combined modility of the selected mitk::NavigationDataSource and mitk::USDevice. **/ void OnCreation(); /** \brief Handles the enabled state of the "Create" button. **/ void OnSelectedUltrasoundOrTrackingDevice(); public: explicit QmitkUSCombinedModalityCreationWidget(QWidget *parent = 0); ~QmitkUSCombinedModalityCreationWidget(); private: Ui::QmitkUSCombinedModalityCreationWidget *ui; + + itk::SmartPointer m_CombinedModality; }; #endif // QMITKUSCOMBINEDMODALITYCREATIONWIDGET_H diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityEditWidget.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityEditWidget.cpp index 2447bd0791..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->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->GetUltrasoundDevice()->SetManufacturer(ui->vendorLineEdit->text().toStdString()); m_CombinedModality->GetUltrasoundDevice()->SetName(ui->nameLineEdit->text().toStdString()); m_LastCalibrations = m_CombinedModality->SerializeCalibration(); } emit SignalSaved(); } void QmitkUSCombinedModalityEditWidget::OnCancelButtonClicked() { if ( m_CombinedModality.IsNotNull() && ! m_LastCalibrations.empty() ) { // restore previous calibrations if cancel button was clicked m_CombinedModality->DeserializeCalibration(m_LastCalibrations); } emit SignalAborted(); } void QmitkUSCombinedModalityEditWidget::OnCalibrationsSaveButtonClicked() { if ( m_CombinedModality.IsNull() ) { MITK_WARN << "Cannot save calibrations as no combined modality is available."; return; } QString filename = QFileDialog::getSaveFileName( QApplication::activeWindow(), "Save Calibrations", "", "Calibration files *.cal" ); QFile file(filename); if ( ! file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate) ) { MITK_WARN << "Cannot open file '" << filename.toStdString() << "' for writing."; return; } std::string calibrationSerialization = m_CombinedModality->SerializeCalibration(); QTextStream outStream(&file); outStream << QString::fromStdString(calibrationSerialization); } void QmitkUSCombinedModalityEditWidget::OnCalibrationsLoadButtonClicked() { if ( m_CombinedModality.IsNull() ) { MITK_WARN << "Cannot load calibrations as no combined modality is available."; return; } QString filename = QFileDialog::getOpenFileName( QApplication::activeWindow(), "Load Calibration", "", "Calibration files *.cal" ); if ( filename.isNull() ) { return; } QFile file(filename); if ( ! file.open(QIODevice::ReadOnly | QIODevice::Text) ) { MITK_WARN << "Cannot open file '" << filename.toStdString() << "' for reading."; return; } QTextStream inStream(&file); std::string calibration = inStream.readAll().toStdString(); if ( calibration.empty() ) { MITK_WARN << "Failed to load file. Unsupported format?"; return; } try { m_CombinedModality->DeserializeCalibration(calibration, false); } catch ( const mitk::Exception& /*exception*/ ) { MITK_WARN << "Failed to deserialize calibration. Unsuppoerted format?"; return; } // make sure that the table model is up to date m_CalibrationsDataModel->SetCombinedModality(m_CombinedModality); } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityEditWidget.h b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityEditWidget.h index 0a97cf70b1..e1a822a14b 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityEditWidget.h +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSCombinedModalityEditWidget.h @@ -1,61 +1,61 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKUSCOMBINEDMODALITYEDITWIDGET_H #define QMITKUSCOMBINEDMODALITYEDITWIDGET_H #include #include "mitkUSCombinedModality.h" namespace Ui { class QmitkUSCombinedModalityEditWidget; } class QmitkUSNavigationCalibrationsDataModel; class QmitkUSNavigationCalibrationUpdateDepthDelegate; class QmitkUSCombinedModalityEditWidget : public QWidget { Q_OBJECT signals: void SignalSaved(); void SignalAborted(); protected slots: void OnSaveButtonClicked(); void OnCancelButtonClicked(); void OnCalibrationsSaveButtonClicked(); void OnCalibrationsLoadButtonClicked(); public: explicit QmitkUSCombinedModalityEditWidget(QWidget *parent = 0); ~QmitkUSCombinedModalityEditWidget(); - void SetCombinedModality(mitk::USCombinedModality::Pointer combinedModality); + void SetCombinedModality(mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality); private: - mitk::USCombinedModality::Pointer m_CombinedModality; + mitk::AbstractUltrasoundTrackerDevice::Pointer m_CombinedModality; std::string m_LastCalibrations; QmitkUSNavigationCalibrationsDataModel* m_CalibrationsDataModel; QmitkUSNavigationCalibrationUpdateDepthDelegate* m_CalibrationUpdateDepthDelegate; Ui::QmitkUSCombinedModalityEditWidget* ui; }; #endif // QMITKUSCOMBINEDMODALITYEDITWIDGET_H diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationFreezeButton.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationFreezeButton.cpp index 149da23a90..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->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->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.h b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationProcessWidget.h index 1a78fd3998..9b5d9975ca 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationProcessWidget.h +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationProcessWidget.h @@ -1,179 +1,179 @@ /*=================================================================== 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_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