diff --git a/Modules/Bundles/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberBundleOperationsView.cpp b/Modules/Bundles/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberBundleOperationsView.cpp index 11d3a6d2c5..a3f38ae33f 100644 --- a/Modules/Bundles/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberBundleOperationsView.cpp +++ b/Modules/Bundles/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberBundleOperationsView.cpp @@ -1,1823 +1,1904 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2010-03-31 16:40:27 +0200 (Mi, 31 Mrz 2010) $ Version: $Revision: 21975 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkFiberBundleOperationsView.h" #include "QmitkStdMultiWidget.h" // Qt #include //MITK #include "mitkNodePredicateProperty.h" //#include "mitkNodePredicateAND.h" #include "mitkImageCast.h" #include "mitkPointSet.h" #include "mitkPlanarCircle.h" #include "mitkPlanarPolygon.h" #include #include "mitkPlanarFigureInteractor.h" #include "mitkGlobalInteraction.h" #include #include #include #include #include #include #include #include +#include const std::string QmitkFiberBundleOperationsView::VIEW_ID = "org.mitk.views.fiberBundleOperations"; const std::string id_DataManager = "org.mitk.views.datamanager"; using namespace berry; using namespace mitk; +struct FboSelListener : ISelectionListener +{ + + berryObjectMacro(FboSelListener); + + FboSelListener(QmitkFiberBundleOperationsView* view) + { + m_View = view; + } + + void DoSelectionChanged(ISelection::ConstPointer selection) + { + // save current selection in member variable + m_View->m_CurrentSelection = selection.Cast(); + + // do something with the selected items + if(m_View->m_CurrentSelection) + { + bool foundFiberBundle = false; + std::string classname = "FiberBundle"; + + // iterate selection + for (IStructuredSelection::iterator i = m_View->m_CurrentSelection->Begin(); + i != m_View->m_CurrentSelection->End(); ++i) + { + + // extract datatree node + if (mitk::DataNodeObject::Pointer nodeObj = i->Cast()) + { + mitk::DataNode::Pointer node = nodeObj->GetDataNode(); + std::string fname = node->GetData()->GetNameOfClass(); + if(node->GetData() && classname.compare(node->GetData()->GetNameOfClass())==0) + { + foundFiberBundle = true; + } + } + } + + if(foundFiberBundle) + { + m_View->m_Controls->m_CircleButton->setEnabled(true); + m_View->m_Controls->m_PolygonButton->setEnabled(true); + m_View->m_Controls->m_RectangleButton->setEnabled(true); + } + else{ + m_View->m_Controls->m_CircleButton->setEnabled(false); + m_View->m_Controls->m_PolygonButton->setEnabled(false); + m_View->m_Controls->m_RectangleButton->setEnabled(false); + } + } + } + + void SelectionChanged(IWorkbenchPart::Pointer part, ISelection::ConstPointer selection) + { + // check, if selection comes from datamanager + if (part) + { + QString partname(part->GetPartName().c_str()); + if(partname.compare("Datamanager")==0) + { + + // apply selection + DoSelectionChanged(selection); + + } + } + } + + QmitkFiberBundleOperationsView* m_View; +}; + QmitkFiberBundleOperationsView::QmitkFiberBundleOperationsView() : QmitkFunctionality() , m_Controls( 0 ) , m_MultiWidget( NULL ) , m_EllipseCounter(0) , m_PolygonCounter(0) //, m_SelectedFBNodes( NULL ) //, m_SelectedPFNodes(0) , m_UpsamplingFactor(5) { } // Destructor QmitkFiberBundleOperationsView::~QmitkFiberBundleOperationsView() { } void QmitkFiberBundleOperationsView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkFiberBundleOperationsViewControls; m_Controls->setupUi( parent ); m_Controls->doExtractFibersButton->setDisabled(true); m_Controls->PFCompoANDButton->setDisabled(true); m_Controls->PFCompoORButton->setDisabled(true); m_Controls->PFCompoNOTButton->setDisabled(true); m_Controls->PFCompoDELButton->setDisabled(true); + m_Controls->m_CircleButton->setEnabled(false); + m_Controls->m_PolygonButton->setEnabled(false); + m_Controls->m_RectangleButton->setEnabled(false); connect( m_Controls->doExtractFibersButton, SIGNAL(clicked()), this, SLOT(DoFiberExtraction()) ); //connect( m_Controls->comboBox_fiberAlgo, SIGNAL(selected()), this, SLOT(handleAlgoSelection() ); connect( m_Controls->m_CircleButton, SIGNAL( clicked() ), this, SLOT( ActionDrawEllipseTriggered() ) ); connect( m_Controls->m_PolygonButton, SIGNAL( clicked() ), this, SLOT( ActionDrawPolygonTriggered() ) ); connect(m_Controls->PFCompoANDButton, SIGNAL(clicked()), this, SLOT(generatePFCompo_AND()) ); connect(m_Controls->PFCompoORButton, SIGNAL(clicked()), this, SLOT(generatePFCompo_OR()) ); connect(m_Controls->PFCompoNOTButton, SIGNAL(clicked()), this, SLOT(generatePFCompo_NOT()) ); connect(m_Controls->PFCompoDELButton, SIGNAL(clicked()), this, SLOT(deletePFCompo()) ); connect(m_Controls->m_JoinBundles, SIGNAL(clicked()), this, SLOT(JoinBundles()) ); connect(m_Controls->m_SubstractBundles, SIGNAL(clicked()), this, SLOT(SubstractBundles()) ); connect(m_Controls->m_GenerateROIImage, SIGNAL(clicked()), this, SLOT(GenerateROIImage()) ); connect( m_Controls->m_GenerationStartButton, SIGNAL(clicked()), this, SLOT(GenerationStart()) ); } + + m_SelListener = berry::ISelectionListener::Pointer(new FboSelListener(this)); + this->GetSite()->GetWorkbenchWindow()->GetSelectionService()->AddPostSelectionListener(/*"org.mitk.views.datamanager",*/ m_SelListener); + berry::ISelection::ConstPointer sel( + this->GetSite()->GetWorkbenchWindow()->GetSelectionService()->GetSelection("org.mitk.views.datamanager")); + m_CurrentSelection = sel.Cast(); + m_SelListener.Cast()->DoSelectionChanged(sel); } void QmitkFiberBundleOperationsView::GenerateROIImage(){ if (m_Image.IsNull() || m_SelectedPF.empty()) return; mitk::Image* image = const_cast(m_Image.GetPointer()); MaskImage3DType::Pointer temp = MaskImage3DType::New(); mitk::CastToItkImage(m_Image, temp); m_PlanarFigureImage = MaskImage3DType::New(); m_PlanarFigureImage->SetSpacing( temp->GetSpacing() ); // Set the image spacing m_PlanarFigureImage->SetOrigin( temp->GetOrigin() ); // Set the image origin m_PlanarFigureImage->SetDirection( temp->GetDirection() ); // Set the image direction m_PlanarFigureImage->SetRegions( temp->GetLargestPossibleRegion() ); m_PlanarFigureImage->Allocate(); m_PlanarFigureImage->FillBuffer( 0 ); for (int i=0; i(m_SelectedPF.at(i)->GetData()), image); DataNode::Pointer node = DataNode::New(); Image::Pointer tmpImage = Image::New(); tmpImage->InitializeByItk(m_PlanarFigureImage.GetPointer()); tmpImage->SetVolume(m_PlanarFigureImage->GetBufferPointer()); node->SetData(tmpImage); node->SetName("planarFigureImage"); this->GetDefaultDataStorage()->Add(node); } void QmitkFiberBundleOperationsView::CompositeExtraction(mitk::PlanarFigure::Pointer planarFigure, mitk::Image* image) { if (dynamic_cast(planarFigure.GetPointer())){ mitk::PlanarFigureComposite::Pointer pfcomp = dynamic_cast(planarFigure.GetPointer()); for (int i=0; igetNumberOfChildren(); ++i) { CompositeExtraction(pfcomp->getChildAt(i), image); } } else { m_PlanarFigure = planarFigure; AccessFixedDimensionByItk_3( image, InternalReorientImagePlane, 3, image->GetGeometry(), m_PlanarFigure->GetGeometry(), -1); AccessFixedDimensionByItk_1( m_InternalImage, InternalCalculateMaskFromPlanarFigure, 3, 2 ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkFiberBundleOperationsView::InternalReorientImagePlane( const itk::Image< TPixel, VImageDimension > *image, mitk::Geometry3D* imggeo, mitk::Geometry3D* planegeo3D, int additionalIndex ) { MITK_INFO << "InternalReorientImagePlane() start"; typedef itk::Image< TPixel, VImageDimension > ImageType; typedef itk::Image< float, VImageDimension > FloatImageType; typedef itk::ResampleImageFilter ResamplerType; typename ResamplerType::Pointer resampler = ResamplerType::New(); mitk::PlaneGeometry* planegeo = dynamic_cast(planegeo3D); float upsamp = m_UpsamplingFactor; float gausssigma = 0.5; // Spacing typename ResamplerType::SpacingType spacing = planegeo->GetSpacing(); spacing[0] = image->GetSpacing()[0] / upsamp; spacing[1] = image->GetSpacing()[1] / upsamp; spacing[2] = image->GetSpacing()[2]; resampler->SetOutputSpacing( spacing ); // Size typename ResamplerType::SizeType size; size[0] = planegeo->GetParametricExtentInMM(0) / spacing[0]; size[1] = planegeo->GetParametricExtentInMM(1) / spacing[1]; size[2] = 1; resampler->SetSize( size ); // Origin typename mitk::Point3D orig = planegeo->GetOrigin(); typename mitk::Point3D corrorig; planegeo3D->WorldToIndex(orig,corrorig); corrorig[0] += 0.5/upsamp; corrorig[1] += 0.5/upsamp; corrorig[2] += 0; planegeo3D->IndexToWorld(corrorig,corrorig); resampler->SetOutputOrigin(corrorig ); // Direction typename ResamplerType::DirectionType direction; typename mitk::AffineTransform3D::MatrixType matrix = planegeo->GetIndexToWorldTransform()->GetMatrix(); for(int c=0; cSetOutputDirection( direction ); // Gaussian interpolation if(gausssigma != 0) { double sigma[3]; for( unsigned int d = 0; d < 3; d++ ) { sigma[d] = gausssigma * image->GetSpacing()[d]; } double alpha = 2.0; typedef itk::GaussianInterpolateImageFunction GaussianInterpolatorType; typename GaussianInterpolatorType::Pointer interpolator = GaussianInterpolatorType::New(); interpolator->SetInputImage( image ); interpolator->SetParameters( sigma, alpha ); resampler->SetInterpolator( interpolator ); } else { // typedef typename itk::BSplineInterpolateImageFunction // InterpolatorType; typedef typename itk::LinearInterpolateImageFunction InterpolatorType; typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); interpolator->SetInputImage( image ); resampler->SetInterpolator( interpolator ); } // Other resampling options resampler->SetInput( image ); resampler->SetDefaultPixelValue(0); MITK_INFO << "Resampling requested image plane ... "; resampler->Update(); MITK_INFO << " ... done"; if(additionalIndex < 0) { this->m_InternalImage = mitk::Image::New(); this->m_InternalImage->InitializeByItk( resampler->GetOutput() ); this->m_InternalImage->SetVolume( resampler->GetOutput()->GetBufferPointer() ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkFiberBundleOperationsView::InternalCalculateMaskFromPlanarFigure( itk::Image< TPixel, VImageDimension > *image, unsigned int axis ) { MITK_INFO << "InternalCalculateMaskFromPlanarFigure() start"; typedef itk::Image< TPixel, VImageDimension > ImageType; typedef itk::CastImageFilter< ImageType, MaskImage3DType > CastFilterType; // Generate mask image as new image with same header as input image and // initialize with "1". MaskImage3DType::Pointer newMaskImage = MaskImage3DType::New(); newMaskImage->SetSpacing( image->GetSpacing() ); // Set the image spacing newMaskImage->SetOrigin( image->GetOrigin() ); // Set the image origin newMaskImage->SetDirection( image->GetDirection() ); // Set the image direction newMaskImage->SetRegions( image->GetLargestPossibleRegion() ); newMaskImage->Allocate(); newMaskImage->FillBuffer( 1 ); // Generate VTK polygon from (closed) PlanarFigure polyline // (The polyline points are shifted by -0.5 in z-direction to make sure // that the extrusion filter, which afterwards elevates all points by +0.5 // in z-direction, creates a 3D object which is cut by the the plane z=0) const Geometry2D *planarFigureGeometry2D = m_PlanarFigure->GetGeometry2D(); const PlanarFigure::PolyLineType planarFigurePolyline = m_PlanarFigure->GetPolyLine( 0 ); const Geometry3D *imageGeometry3D = m_InternalImage->GetGeometry( 0 ); vtkPolyData *polyline = vtkPolyData::New(); polyline->Allocate( 1, 1 ); // Determine x- and y-dimensions depending on principal axis int i0, i1; switch ( axis ) { case 0: i0 = 1; i1 = 2; break; case 1: i0 = 0; i1 = 2; break; case 2: default: i0 = 0; i1 = 1; break; } // Create VTK polydata object of polyline contour vtkPoints *points = vtkPoints::New(); PlanarFigure::PolyLineType::const_iterator it; std::vector indices; unsigned int numberOfPoints = 0; for ( it = planarFigurePolyline.begin(); it != planarFigurePolyline.end(); ++it ) { Point3D point3D; // Convert 2D point back to the local index coordinates of the selected // image Point2D point2D = it->Point; planarFigureGeometry2D->WorldToIndex(point2D, point2D); point2D[0] -= 0.5/m_UpsamplingFactor; point2D[1] -= 0.5/m_UpsamplingFactor; planarFigureGeometry2D->IndexToWorld(point2D, point2D); planarFigureGeometry2D->Map( point2D, point3D ); // Polygons (partially) outside of the image bounds can not be processed // further due to a bug in vtkPolyDataToImageStencil if ( !imageGeometry3D->IsInside( point3D ) ) { float bounds[2] = {0,0}; bounds[0] = this->m_InternalImage->GetLargestPossibleRegion().GetSize().GetElement(i0); bounds[1] = this->m_InternalImage->GetLargestPossibleRegion().GetSize().GetElement(i1); imageGeometry3D->WorldToIndex( point3D, point3D ); if (point3D[i0]<0) point3D[i0] = 0.5; else if (point3D[i0]>bounds[0]) point3D[i0] = bounds[0]-0.5; if (point3D[i1]<0) point3D[i1] = 0.5; else if (point3D[i1]>bounds[1]) point3D[i1] = bounds[1]-0.5; points->InsertNextPoint( point3D[i0], point3D[i1], -0.5 ); numberOfPoints++; } else { imageGeometry3D->WorldToIndex( point3D, point3D ); point3D[i0] += 0.5; point3D[i1] += 0.5; // Add point to polyline array points->InsertNextPoint( point3D[i0], point3D[i1], -0.5 ); numberOfPoints++; } } polyline->SetPoints( points ); points->Delete(); vtkIdType *ptIds = new vtkIdType[numberOfPoints]; for ( vtkIdType i = 0; i < numberOfPoints; ++i ) { ptIds[i] = i; } polyline->InsertNextCell( VTK_POLY_LINE, numberOfPoints, ptIds ); // Extrude the generated contour polygon vtkLinearExtrusionFilter *extrudeFilter = vtkLinearExtrusionFilter::New(); extrudeFilter->SetInput( polyline ); extrudeFilter->SetScaleFactor( 1 ); extrudeFilter->SetExtrusionTypeToNormalExtrusion(); extrudeFilter->SetVector( 0.0, 0.0, 1.0 ); // Make a stencil from the extruded polygon vtkPolyDataToImageStencil *polyDataToImageStencil = vtkPolyDataToImageStencil::New(); polyDataToImageStencil->SetInput( extrudeFilter->GetOutput() ); // Export from ITK to VTK (to use a VTK filter) typedef itk::VTKImageImport< MaskImage3DType > ImageImportType; typedef itk::VTKImageExport< MaskImage3DType > ImageExportType; typename ImageExportType::Pointer itkExporter = ImageExportType::New(); itkExporter->SetInput( newMaskImage ); vtkImageImport *vtkImporter = vtkImageImport::New(); this->ConnectPipelines( itkExporter, vtkImporter ); vtkImporter->Update(); // Apply the generated image stencil to the input image vtkImageStencil *imageStencilFilter = vtkImageStencil::New(); imageStencilFilter->SetInputConnection( vtkImporter->GetOutputPort() ); imageStencilFilter->SetStencil( polyDataToImageStencil->GetOutput() ); imageStencilFilter->ReverseStencilOff(); imageStencilFilter->SetBackgroundValue( 0 ); imageStencilFilter->Update(); // Export from VTK back to ITK vtkImageExport *vtkExporter = vtkImageExport::New(); vtkExporter->SetInputConnection( imageStencilFilter->GetOutputPort() ); vtkExporter->Update(); typename ImageImportType::Pointer itkImporter = ImageImportType::New(); this->ConnectPipelines( vtkExporter, itkImporter ); itkImporter->Update(); // calculate cropping bounding box m_InternalImageMask3D = itkImporter->GetOutput(); m_InternalImageMask3D->SetDirection(image->GetDirection()); itk::ImageRegionConstIterator itmask(m_InternalImageMask3D, m_InternalImageMask3D->GetLargestPossibleRegion()); itk::ImageRegionIterator itimage(image, image->GetLargestPossibleRegion()); itmask = itmask.Begin(); itimage = itimage.Begin(); typename ImageType::SizeType lowersize = {{9999999999,9999999999,9999999999}}; typename ImageType::SizeType uppersize = {{0,0,0}}; while( !itmask.IsAtEnd() ) { if(itmask.Get() == 0) { itimage.Set(0); } else { typename ImageType::IndexType index = itimage.GetIndex(); typename ImageType::SizeType signedindex; signedindex[0] = index[0]; signedindex[1] = index[1]; signedindex[2] = index[2]; lowersize[0] = signedindex[0] < lowersize[0] ? signedindex[0] : lowersize[0]; lowersize[1] = signedindex[1] < lowersize[1] ? signedindex[1] : lowersize[1]; lowersize[2] = signedindex[2] < lowersize[2] ? signedindex[2] : lowersize[2]; uppersize[0] = signedindex[0] > uppersize[0] ? signedindex[0] : uppersize[0]; uppersize[1] = signedindex[1] > uppersize[1] ? signedindex[1] : uppersize[1]; uppersize[2] = signedindex[2] > uppersize[2] ? signedindex[2] : uppersize[2]; } ++itmask; ++itimage; } typename ImageType::IndexType index; index[0] = lowersize[0]; index[1] = lowersize[1]; index[2] = lowersize[2]; typename ImageType::SizeType size; size[0] = uppersize[0] - lowersize[0] + 1; size[1] = uppersize[1] - lowersize[1] + 1; size[2] = uppersize[2] - lowersize[2] + 1; itk::ImageRegion<3> cropRegion = itk::ImageRegion<3>(index, size); // // crop internal image // typedef itk::RegionOfInterestImageFilter< ImageType, ImageType > ROIFilterType; // typename ROIFilterType::Pointer roi = ROIFilterType::New(); // roi->SetRegionOfInterest(cropRegion); // roi->SetInput(image); // roi->Update(); // m_InternalImage = mitk::Image::New(); // m_InternalImage->InitializeByItk(roi->GetOutput()); // m_InternalImage->SetVolume(roi->GetOutput()->GetBufferPointer()); // crop internal mask typedef itk::RegionOfInterestImageFilter< MaskImage3DType, MaskImage3DType > ROIMaskFilterType; typename ROIMaskFilterType::Pointer roi2 = ROIMaskFilterType::New(); roi2->SetRegionOfInterest(cropRegion); roi2->SetInput(m_InternalImageMask3D); roi2->Update(); m_InternalImageMask3D = roi2->GetOutput(); DataNode::Pointer node = DataNode::New(); Image::Pointer tmpImage = Image::New(); tmpImage->InitializeByItk(m_InternalImageMask3D.GetPointer()); tmpImage->SetVolume(m_InternalImageMask3D->GetBufferPointer()); node->SetData(tmpImage); this->GetDefaultDataStorage()->Add(node); Image::Pointer tmpImage2 = Image::New(); tmpImage2->InitializeByItk(m_PlanarFigureImage.GetPointer()); const Geometry3D *pfImageGeometry3D = tmpImage2->GetGeometry( 0 ); const Geometry3D *intImageGeometry3D = tmpImage->GetGeometry( 0 ); typedef itk::ImageRegionIteratorWithIndex IteratorType; IteratorType imageIterator (m_InternalImageMask3D, m_InternalImageMask3D->GetRequestedRegion()); imageIterator.GoToBegin(); while ( !imageIterator.IsAtEnd() ) { unsigned char val = imageIterator.Value(); if (val>0) { itk::Index<3> index = imageIterator.GetIndex(); Point3D point; point[0] = index[0]; point[1] = index[1]; point[2] = index[2]; intImageGeometry3D->IndexToWorld(point, point); pfImageGeometry3D->WorldToIndex(point, point); index[0] = point[0]; index[1] = point[1]; index[2] = point[2]; m_PlanarFigureImage->SetPixel(index, 1); } ++imageIterator; } // Clean up VTK objects polyline->Delete(); extrudeFilter->Delete(); polyDataToImageStencil->Delete(); vtkImporter->Delete(); imageStencilFilter->Delete(); //vtkExporter->Delete(); // TODO: crashes when outcommented; memory leak?? delete[] ptIds; } void QmitkFiberBundleOperationsView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } void QmitkFiberBundleOperationsView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } /* OnSelectionChanged is registered to SelectionService, therefore no need to implement SelectionService Listener explicitly */ void QmitkFiberBundleOperationsView::OnSelectionChanged( std::vector nodes ) { if ( !this->IsVisible() ) { // do nothing if nobody wants to see me :-( return; } //reset existing Vectors containing FiberBundles and PlanarFigures from a previous selection m_SelectedFB.clear(); m_SelectedPF.clear(); m_Image = NULL; //differ between 2 scenarios... // 1) add PF to an existing Spaghetti // 2) BOOLEAN OPERATORS HANDLING ... selection of multiple PF, and or multiple Spaghetti //scenario 1 for( std::vector::iterator it = nodes.begin(); it != nodes.end(); ++it ) { mitk::DataNode::Pointer node = *it; if ( dynamic_cast(node->GetData()) ) { // MITK_INFO << "onselectionchg(): " << node->GetData()->GetNameOfClass(); m_SelectedFB.push_back(node); mitk::FiberBundle::Pointer bundle = dynamic_cast(node->GetData()); QString numFibers; this->m_Controls->m_NumFibersLabel->setText(numFibers.setNum(bundle->GetNumTracts())); } else if (dynamic_cast(node->GetData())){ // MITK_INFO << "onselectionchg(): " << node->GetData()->GetNameOfClass(); m_SelectedPF.push_back(node); } else if (dynamic_cast(node->GetData())){ m_Image = dynamic_cast(node->GetData()); } } if (m_SelectedPF.size() >= 1 && m_Image.IsNotNull()) m_Controls->m_GenerateROIImage->setEnabled(true); else m_Controls->m_GenerateROIImage->setEnabled(false); //quick and dirty control structure for extraction ATM if (m_SelectedPF.size() == 1) { //############################################# //### PLANAR FIGURE COMPOSIT SelectionLOGIC ### //############################################# m_Controls->PFCompoANDButton->setDisabled(true); m_Controls->PFCompoORButton->setDisabled(true); m_Controls->PFCompoNOTButton->setEnabled(true); m_Controls->PFCompoDELButton->setDisabled(true); //if planarFigureComposite selected, activate DEL button if ( dynamic_cast(m_SelectedPF.at(0)->GetData()) ) { m_Controls->PFCompoDELButton->setEnabled(true); } } else if (m_SelectedPF.size() > 1) { //############################################# //### PLANAR FIGURE COMPOSIT SelectionLOGIC ### //############################################# // if 2 PlanarFigure objects (PFCircle, PFPoly, ..., PFComposite) selected, //then activate AND OR NOT PF Composite Buttons m_Controls->PFCompoANDButton->setEnabled(true); m_Controls->PFCompoORButton->setEnabled(true); m_Controls->PFCompoNOTButton->setDisabled(true); m_Controls->PFCompoDELButton->setDisabled(true); } if (m_SelectedFB.size() == 1 && m_SelectedPF.size() == 1) { //############################################# //##### EXTRACT FIBERBUNDLE SelectionLOGIC #### //############################################# m_Controls->doExtractFibersButton->setEnabled(true); } else if (nodes.size() > 1 ) { //scenario 2 } else if (nodes.empty()) { //############################################# //##### EXTRACT FIBERBUNDLE SelectionLOGIC #### //############################################# m_Controls->doExtractFibersButton->setDisabled(true); //############################################# //### PLANAR FIGURE COMPOSIT SelectionLOGIC ### //############################################# m_Controls->PFCompoANDButton->setDisabled(true); m_Controls->PFCompoORButton->setDisabled(true); m_Controls->PFCompoNOTButton->setDisabled(true); } if (m_SelectedFB.size() == 2) { //############################################# //##### JOIN/SUBSTRACT FIBERBUNDLES #### //############################################# m_Controls->m_JoinBundles->setEnabled(true); m_Controls->m_SubstractBundles->setEnabled(true); } else { m_Controls->m_JoinBundles->setEnabled(false); m_Controls->m_SubstractBundles->setEnabled(false); } } void QmitkFiberBundleOperationsView::ActionDrawPolygonTriggered() { // bool checked = m_Controls->m_PolygonButton->isChecked(); // if(!this->AssertDrawingIsPossible(checked)) // return; mitk::PlanarPolygon::Pointer figure = mitk::PlanarPolygon::New(); figure->ClosedOn(); this->AddFigureToDataStorage(figure, QString("Polygon%1").arg(++m_PolygonCounter)); MITK_INFO << "PlanarPolygon created ..."; mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDefaultDataStorage()->GetAll(); mitk::DataNode* node = 0; mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; mitk::PlanarFigure* figureP = 0; for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() ; it++) { node = const_cast(it->Value().GetPointer()); figureP = dynamic_cast(node->GetData()); if(figureP) { figureInteractor = dynamic_cast(node->GetInteractor()); if(figureInteractor.IsNull()) figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", node); mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); } } } void QmitkFiberBundleOperationsView::ActionDrawEllipseTriggered() { //bool checked = m_Controls->m_CircleButton->isChecked(); //if(!this->AssertDrawingIsPossible(checked)) // return; mitk::PlanarCircle::Pointer figure = mitk::PlanarCircle::New(); this->AddFigureToDataStorage(figure, QString("Circle%1").arg(++m_EllipseCounter)); this->GetDataStorage()->Modified(); MITK_INFO << "PlanarCircle created ..."; //call mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDefaultDataStorage()->GetAll(); mitk::DataNode* node = 0; mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; mitk::PlanarFigure* figureP = 0; for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() ; it++) { node = const_cast(it->Value().GetPointer()); figureP = dynamic_cast(node->GetData()); if(figureP) { figureInteractor = dynamic_cast(node->GetInteractor()); if(figureInteractor.IsNull()) figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", node); mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); } } - } void QmitkFiberBundleOperationsView::Activated() { MITK_INFO << "FB OPerations ACTIVATED()"; /* mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDefaultDataStorage()->GetAll(); mitk::DataNode* node = 0; mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; mitk::PlanarFigure* figure = 0; for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() ; it++) { node = const_cast(it->Value().GetPointer()); figure = dynamic_cast(node->GetData()); if(figure) { figureInteractor = dynamic_cast(node->GetInteractor()); if(figureInteractor.IsNull()) figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", node); mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); } } */ } void QmitkFiberBundleOperationsView::AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *propertyKey, mitk::BaseProperty *property ) { //set desired data to DataNode where Planarfigure is stored mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetName(name.toStdString()); newNode->SetData(figure); newNode->AddProperty( "planarfigure.default.line.color", mitk::ColorProperty::New(1.0,0.0,0.0)); newNode->AddProperty( "planarfigure.line.width", mitk::FloatProperty::New(2.0)); newNode->AddProperty( "planarfigure.drawshadow", mitk::BoolProperty::New(true)); newNode->AddProperty( "selected", mitk::BoolProperty::New(true) ); newNode->AddProperty( "planarfigure.ishovering", mitk::BoolProperty::New(true) ); newNode->AddProperty( "planarfigure.drawoutline", mitk::BoolProperty::New(true) ); newNode->AddProperty( "planarfigure.drawquantities", mitk::BoolProperty::New(false) ); newNode->AddProperty( "planarfigure.drawshadow", mitk::BoolProperty::New(true) ); newNode->AddProperty( "planarfigure.line.width", mitk::FloatProperty::New(3.0) ); newNode->AddProperty( "planarfigure.shadow.widthmodifier", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.outline.width", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.helperline.width", mitk::FloatProperty::New(2.0) ); // PlanarFigureControlPointStyleProperty::Pointer styleProperty = // dynamic_cast< PlanarFigureControlPointStyleProperty* >( node->GetProperty( "planarfigure.controlpointshape" ) ); // if ( styleProperty.IsNotNull() ) // { // m_ControlPointShape = styleProperty->GetShape(); // } newNode->AddProperty( "planarfigure.default.line.color", mitk::ColorProperty::New(1.0,1.0,1.0) ); newNode->AddProperty( "planarfigure.default.line.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.outline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.default.outline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.helperline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.default.helperline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.markerline.color", mitk::ColorProperty::New(0.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.default.markerline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.marker.color", mitk::ColorProperty::New(1.0,1.0,1.0) ); newNode->AddProperty( "planarfigure.default.marker.opacity",mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.line.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.line.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.outline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.outline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.helperline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.helperline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.markerline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.markerline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.marker.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.marker.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.selected.line.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.line.opacity",mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.selected.outline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.outline.opacity", mitk::FloatProperty::New(2.0)); newNode->AddProperty( "planarfigure.selected.helperline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.helperline.opacity",mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.selected.markerline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.markerline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.selected.marker.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.marker.opacity",mitk::FloatProperty::New(2.0)); // Add custom property, if available //if ( (propertyKey != NULL) && (property != NULL) ) //{ // newNode->AddProperty( propertyKey, property ); //} //get current selected DataNode -which should be a FiberBundle- and set PlanarFigure as child //this->GetDataStorage()->GetNodes() // mitk::FiberBundle::Pointer selectedFBNode = m_SelectedFBNodes.at(0); // figure drawn on the topmost layer / image this->GetDataStorage()->Add(newNode ); std::vector selectedNodes = GetDataManagerSelection(); for(unsigned int i = 0; i < selectedNodes.size(); i++) { selectedNodes[i]->SetSelected(false); } //selectedNodes = m_SelectedPlanarFigureNodes->GetNodes(); /*for(unsigned int i = 0; i < selectedNodes.size(); i++) { selectedNodes[i]->SetSelected(false); } */ newNode->SetSelected(true); //Select(newNode); } void QmitkFiberBundleOperationsView::DoFiberExtraction() { mitk::FiberBundle::Pointer selFB = dynamic_cast(m_SelectedFB.at(0)->GetData()); mitk::PlanarFigure::Pointer selPF = dynamic_cast (m_SelectedPF.at(0)->GetData()); std::vector extFBset = selFB->extractFibersByPF(selPF); //MITK_INFO << "returned vector in FBOperationsView: " << extFBset.size(); // for(std::vector::iterator dispIt = extFBset.begin(); dispIt != extFBset.end(); dispIt++) // { // MITK_INFO << "vector DTI ID: " << *dispIt; // // } mitk::FiberBundle::Pointer extFB = selFB->extractFibersById(extFBset); MITK_INFO << " Number Of Tracts in sourceFiberBundle: " << selFB->GetNumTracts(); MITK_INFO << " Number Of Tracts in extractedFiberBundle: " << extFB->GetNumTracts(); mitk::DataNode::Pointer fbNode; fbNode = mitk::DataNode::New(); fbNode->SetData(extFB); fbNode->SetName("extGroupFinberBundle"); fbNode->SetVisibility(true); GetDataStorage()->Add(fbNode); } void QmitkFiberBundleOperationsView::generatePFCompo_AND() { mitk::PlanarFigureComposite::Pointer PFCAnd = mitk::PlanarFigureComposite::New(); PFCAnd->setOperationType(mitk::PFCOMPOSITION_AND_OPERATION); for( std::vector::iterator it = m_SelectedPF.begin(); it != m_SelectedPF.end(); ++it ) { mitk::DataNode::Pointer nodePF = *it; mitk::PlanarFigure::Pointer tmpPF = dynamic_cast( nodePF->GetData() ); PFCAnd->addPlanarFigure( tmpPF ); PFCAnd->addDataNode( nodePF ); PFCAnd->setDisplayName("AND_COMPO"); // MITK_INFO << "PFCAND(): added to AND PF" << nodePF->GetName(); } debugPFComposition(PFCAnd, 0); this->addPFCompositionToDataStorage(PFCAnd, NULL /*parent*/); } void QmitkFiberBundleOperationsView::debugPFComposition(mitk::PlanarFigureComposite::Pointer pfc, int itLevelStatus) { int myLevel = itLevelStatus; if (myLevel == 0) { MITK_INFO << "############################################## " ; MITK_INFO << "######### DEBUG START ############## " ; MITK_INFO << "############################################## " ; } MITK_INFO << "############################################## " ; MITK_INFO << "Name: " << pfc->getDisplayName(); MITK_INFO << "iterationLevel: " << myLevel; MITK_INFO << "CompositionType: " << pfc->getOperationType(); MITK_INFO << "Number of children: " << pfc->getNumberOfChildren(); //iterate through pfcs children for(int i=0; igetNumberOfChildren(); ++i) { mitk::PlanarFigure::Pointer tmpPFchild = pfc->getChildAt(i); mitk::DataNode::Pointer savedPFchildNode = pfc->getDataNodeAt(i); if (tmpPFchild == savedPFchildNode->GetData()) { MITK_INFO << "[OK] Pointers point to same Data..."; }else{ MITK_INFO << "Pointers differ in equation"; } MITK_INFO << "Level: " << myLevel << " ChildNr.: " << i ; mitk::PlanarFigureComposite::Pointer pfcompcastNode= dynamic_cast(savedPFchildNode->GetData()); mitk::PlanarFigureComposite::Pointer pfcompcast= dynamic_cast(tmpPFchild.GetPointer()); if( !pfcompcast.IsNull() ) { // we have a composite as child if ( pfcompcastNode.IsNull() ) { MITK_INFO << "************** NODE DIFFER FROM PFC...ERROR! ***************"; } else { MITK_INFO << "[OK]...node contains right type "; } itLevelStatus++; MITK_INFO << "child is PFC...debug this PFC"; debugPFComposition(pfcompcast, itLevelStatus); } else { // we have a planarFigure as child // figure out which type mitk::PlanarCircle::Pointer circleName = mitk::PlanarCircle::New(); mitk::PlanarRectangle::Pointer rectName = mitk::PlanarRectangle::New(); mitk::PlanarPolygon::Pointer polyName = mitk::PlanarPolygon::New(); if (tmpPFchild->GetNameOfClass() == circleName->GetNameOfClass() ) { MITK_INFO << "a circle child of " << pfc->getDisplayName() ; } else if (tmpPFchild->GetNameOfClass() == rectName->GetNameOfClass() ){ MITK_INFO << "a rectangle child of " << pfc->getDisplayName() ; } else if (tmpPFchild->GetNameOfClass() == polyName->GetNameOfClass() ) { MITK_INFO << "a polygon child of " << pfc->getDisplayName() ; } MITK_INFO << "....................................................... " ; } } //end for if (myLevel == 0) { MITK_INFO << "############################################## " ; MITK_INFO << "######### DEBUG END ############## " ; MITK_INFO << "############################################## " ; } } void QmitkFiberBundleOperationsView::generatePFCompo_OR() { mitk::PlanarFigureComposite::Pointer PFCOr = mitk::PlanarFigureComposite::New(); PFCOr->setOperationType(mitk::PFCOMPOSITION_OR_OPERATION); for( std::vector::iterator it = m_SelectedPF.begin(); it != m_SelectedPF.end(); ++it ) { mitk::DataNode::Pointer nodePF = *it; mitk::PlanarFigure::Pointer tmpPF = dynamic_cast( nodePF->GetData() ); PFCOr->addPlanarFigure( tmpPF ); PFCOr->addDataNode( nodePF ); PFCOr->setDisplayName("OR_COMPO"); // MITK_INFO << "PFCAND(): added to AND PF" << nodePF->GetName(); } debugPFComposition(PFCOr, 0); this->addPFCompositionToDataStorage(PFCOr, NULL /*parent*/); } void QmitkFiberBundleOperationsView::generatePFCompo_NOT() { mitk::PlanarFigureComposite::Pointer PFCNot = mitk::PlanarFigureComposite::New(); PFCNot->setOperationType(mitk::PFCOMPOSITION_NOT_OPERATION); for( std::vector::iterator it = m_SelectedPF.begin(); it != m_SelectedPF.end(); ++it ) { mitk::DataNode::Pointer nodePF = *it; mitk::PlanarFigure::Pointer tmpPF = dynamic_cast( nodePF->GetData() ); PFCNot->addPlanarFigure( tmpPF ); PFCNot->addDataNode( nodePF ); PFCNot->setDisplayName("NOT_COMPO"); // MITK_INFO << "PFCAND(): added to AND PF" << nodePF->GetName(); } debugPFComposition(PFCNot, 0); this->addPFCompositionToDataStorage(PFCNot, NULL /*parent*/); } void QmitkFiberBundleOperationsView::deletePFCompo() { } void QmitkFiberBundleOperationsView::addPFCompositionToDataStorage(mitk::PlanarFigureComposite::Pointer pfcomp, mitk::DataNode::Pointer parentDataNode ) { //a new planarFigureComposition arrived //convert it into a dataNode mitk::DataNode::Pointer newPFCNode; newPFCNode = mitk::DataNode::New(); newPFCNode->SetName( pfcomp->getDisplayName() ); //MITK_INFO << "PFComp Name: " << pfcomp->getDisplayName() << " newPFCNodeName: " << newPFCNode->GetName(); newPFCNode->SetData(pfcomp); newPFCNode->SetVisibility(true); switch (pfcomp->getOperationType()) { case 0: { // AND PLANARFIGURECOMPOSITE // newPFCNode->SetName("AND_PFCombo"); if (!parentDataNode.IsNull()) { MITK_INFO << "adding " << newPFCNode->GetName() << " to " << parentDataNode->GetName() ; GetDataStorage()->Add(newPFCNode, parentDataNode); } else { MITK_INFO << "adding " << newPFCNode->GetName(); GetDataStorage()->Add(newPFCNode); } //iterate through its childs for(int i=0; igetNumberOfChildren(); ++i) { mitk::PlanarFigure::Pointer tmpPFchild = pfcomp->getChildAt(i); mitk::DataNode::Pointer savedPFchildNode = pfcomp->getDataNodeAt(i); mitk::PlanarFigureComposite::Pointer pfcompcast= dynamic_cast(tmpPFchild.GetPointer()); if ( !pfcompcast.IsNull() ) { // child is of type planar Figure composite // make new node of the child, cuz later the child has to be removed of its old position in datamanager // feed new dataNode with information of the savedDataNode, which is gonna be removed soon mitk::DataNode::Pointer newChildPFCNode; newChildPFCNode = mitk::DataNode::New(); newChildPFCNode->SetData(tmpPFchild); newChildPFCNode->SetName( savedPFchildNode->GetName() ); pfcompcast->setDisplayName( savedPFchildNode->GetName() ); //name might be changed in DataManager by user //update inside vector the dataNodePointer pfcomp->replaceDataNodeAt(i, newChildPFCNode); addPFCompositionToDataStorage(pfcompcast, newPFCNode); //the current PFCNode becomes the childs parent // remove savedNode here, cuz otherwise its children will change their position in the dataNodeManager // without having its parent anymore //GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_INFO << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " still exists"; } } else { // child is not of type PlanarFigureComposite, so its one of the planarFigures // create new dataNode containing the data of the old dataNode, but position in dataManager will be // modified cuz we re setting a (new) parent. mitk::DataNode::Pointer newPFchildNode = mitk::DataNode::New(); newPFchildNode->SetName(savedPFchildNode->GetName() ); newPFchildNode->SetData(tmpPFchild); newPFchildNode->SetVisibility(true); // replace the dataNode in PFComp DataNodeVector pfcomp->replaceDataNodeAt(i, newPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_INFO << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " still exists"; } MITK_INFO << "adding " << newPFchildNode->GetName() << " to " << newPFCNode->GetName(); //add new child to datamanager with its new position as child of newPFCNode parent GetDataStorage()->Add(newPFchildNode, newPFCNode); } } GetDataStorage()->Modified(); break; } case 1: { // AND PLANARFIGURECOMPOSITE // newPFCNode->SetName("AND_PFCombo"); if (!parentDataNode.IsNull()) { MITK_INFO << "adding " << newPFCNode->GetName() << " to " << parentDataNode->GetName() ; GetDataStorage()->Add(newPFCNode, parentDataNode); } else { MITK_INFO << "adding " << newPFCNode->GetName(); GetDataStorage()->Add(newPFCNode); } //iterate through its childs for(int i=0; igetNumberOfChildren(); ++i) { mitk::PlanarFigure::Pointer tmpPFchild = pfcomp->getChildAt(i); mitk::DataNode::Pointer savedPFchildNode = pfcomp->getDataNodeAt(i); mitk::PlanarFigureComposite::Pointer pfcompcast= dynamic_cast(tmpPFchild.GetPointer()); if ( !pfcompcast.IsNull() ) { // child is of type planar Figure composite // make new node of the child, cuz later the child has to be removed of its old position in datamanager // feed new dataNode with information of the savedDataNode, which is gonna be removed soon mitk::DataNode::Pointer newChildPFCNode; newChildPFCNode = mitk::DataNode::New(); newChildPFCNode->SetData(tmpPFchild); newChildPFCNode->SetName( savedPFchildNode->GetName() ); pfcompcast->setDisplayName( savedPFchildNode->GetName() ); //name might be changed in DataManager by user //update inside vector the dataNodePointer pfcomp->replaceDataNodeAt(i, newChildPFCNode); addPFCompositionToDataStorage(pfcompcast, newPFCNode); //the current PFCNode becomes the childs parent // remove savedNode here, cuz otherwise its children will change their position in the dataNodeManager // without having its parent anymore //GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_INFO << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " still exists"; } } else { // child is not of type PlanarFigureComposite, so its one of the planarFigures // create new dataNode containing the data of the old dataNode, but position in dataManager will be // modified cuz we re setting a (new) parent. mitk::DataNode::Pointer newPFchildNode = mitk::DataNode::New(); newPFchildNode->SetName(savedPFchildNode->GetName() ); newPFchildNode->SetData(tmpPFchild); newPFchildNode->SetVisibility(true); // replace the dataNode in PFComp DataNodeVector pfcomp->replaceDataNodeAt(i, newPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_INFO << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " still exists"; } MITK_INFO << "adding " << newPFchildNode->GetName() << " to " << newPFCNode->GetName(); //add new child to datamanager with its new position as child of newPFCNode parent GetDataStorage()->Add(newPFchildNode, newPFCNode); } } GetDataStorage()->Modified(); break; } case 2: { // AND PLANARFIGURECOMPOSITE // newPFCNode->SetName("AND_PFCombo"); if (!parentDataNode.IsNull()) { MITK_INFO << "adding " << newPFCNode->GetName() << " to " << parentDataNode->GetName() ; GetDataStorage()->Add(newPFCNode, parentDataNode); } else { MITK_INFO << "adding " << newPFCNode->GetName(); GetDataStorage()->Add(newPFCNode); } //iterate through its childs for(int i=0; igetNumberOfChildren(); ++i) { mitk::PlanarFigure::Pointer tmpPFchild = pfcomp->getChildAt(i); mitk::DataNode::Pointer savedPFchildNode = pfcomp->getDataNodeAt(i); mitk::PlanarFigureComposite::Pointer pfcompcast= dynamic_cast(tmpPFchild.GetPointer()); if ( !pfcompcast.IsNull() ) { // child is of type planar Figure composite // makeRemoveBundle new node of the child, cuz later the child has to be removed of its old position in datamanager // feed new dataNode with information of the savedDataNode, which is gonna be removed soon mitk::DataNode::Pointer newChildPFCNode; newChildPFCNode = mitk::DataNode::New(); newChildPFCNode->SetData(tmpPFchild); newChildPFCNode->SetName( savedPFchildNode->GetName() ); pfcompcast->setDisplayName( savedPFchildNode->GetName() ); //name might be changed in DataManager by user //update inside vector the dataNodePointer pfcomp->replaceDataNodeAt(i, newChildPFCNode); addPFCompositionToDataStorage(pfcompcast, newPFCNode); //the current PFCNode becomes the childs parent // remove savedNode here, cuz otherwise its children will change their position in the dataNodeManager // without having its parent anymore //GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_INFO << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " still exists"; } } else { // child is not of type PlanarFigureComposite, so its one of the planarFigures // create new dataNode containing the data of the old dataNode, but position in dataManager will be // modified cuz we re setting a (new) parent. mitk::DataNode::Pointer newPFchildNode = mitk::DataNode::New(); newPFchildNode->SetName(savedPFchildNode->GetName() ); newPFchildNode->SetData(tmpPFchild); newPFchildNode->SetVisibility(true); // replace the dataNode in PFComp DataNodeVector pfcomp->replaceDataNodeAt(i, newPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_INFO << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " still exists"; } MITK_INFO << "adding " << newPFchildNode->GetName() << " to " << newPFCNode->GetName(); //add new child to datamanager with its new position as child of newPFCNode parent GetDataStorage()->Add(newPFchildNode, newPFCNode); } } GetDataStorage()->Modified(); break; } default: MITK_INFO << "we have an UNDEFINED composition... ERROR" ; break; } } void QmitkFiberBundleOperationsView::JoinBundles() { mitk::FiberBundle::Pointer bundle1 = dynamic_cast(m_SelectedFB.at(0)->GetData()); mitk::FiberBundle::Pointer bundle2 = dynamic_cast(m_SelectedFB.at(1)->GetData()); mitk::FiberBundle::Pointer newBundle = bundle1->JoinBundle(bundle2); mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName(m_SelectedFB.at(0)->GetName()+"+"+m_SelectedFB.at(1)->GetName()); fbNode->SetVisibility(true); GetDataStorage()->Add(fbNode); } void QmitkFiberBundleOperationsView::SubstractBundles() { mitk::FiberBundle::Pointer bundle1 = dynamic_cast(m_SelectedFB.at(0)->GetData()); mitk::FiberBundle::Pointer bundle2 = dynamic_cast(m_SelectedFB.at(1)->GetData()); mitk::FiberBundle::Pointer newBundle = bundle1->SubstractBundle(bundle2); mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName(m_SelectedFB.at(0)->GetName()+"-"+m_SelectedFB.at(1)->GetName()); fbNode->SetVisibility(true); GetDataStorage()->Add(fbNode); } void QmitkFiberBundleOperationsView::GenerationStart() { int generationMethod = m_Controls->m_GenerationBox->currentIndex(); std::vector nodes = GetDataManagerSelection(); if (nodes.empty()){ QMessageBox::information( NULL, "Warning", "No data object selected!"); MITK_WARN("QmitkFiberBundleOperationsView") << "no data object selected"; return; } for( std::vector::iterator it = nodes.begin(); it != nodes.end(); ++it ) { mitk::DataNode::Pointer node = *it; if (node.IsNotNull() && dynamic_cast(node->GetData())) { m_FiberBundle = dynamic_cast(node->GetData()); m_FiberBundleNode = node; switch(generationMethod){ case 0: GenerateGreyscaleHeatmap(true); break; case 1: GenerateGreyscaleHeatmap(false); break; case 2: GenerateColorHeatmap(); break; case 3: GenerateFiberEndingsImage(); break; case 4: GenerateFiberEndingsPointSet(); break; case 5: DWIGenerationStart(); break; } } } } // generate pointset displaying the fiber endings void QmitkFiberBundleOperationsView::GenerateFiberEndingsPointSet() { if(m_FiberBundle.IsNull()){ QMessageBox::information( NULL, "Warning", "No fiber bundle selected!"); MITK_WARN("QmitkGlobalFiberTrackingView") << "no fiber bundle selected"; return; } mitk::Geometry3D::Pointer geometry = m_FiberBundle->GetGeometry(); mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); int numTracts = m_FiberBundle->GetNumTracts(); int count = 0; for( int i=0; iGetNumPoints(i); itk::Point start = m_FiberBundle->GetPoint(i,0); itk::Point world1; geometry->IndexToWorld(start, world1); pointSet->InsertPoint(count, world1); count++; // get fiber end point if(numVertices>1) { itk::Point end = m_FiberBundle->GetPoint(i,numVertices-1); itk::Point world; geometry->IndexToWorld(end, world); pointSet->InsertPoint(count, world); count++; } } mitk::DataNode::Pointer pointSetNode = mitk::DataNode::New(); pointSetNode->SetData( pointSet ); QString name(m_FiberBundleNode->GetName().c_str()); name += "_fiber_endings"; pointSetNode->SetName(name.toStdString()); pointSetNode->SetProperty( "opacity", mitk::FloatProperty::New( 1 ) ); pointSetNode->SetProperty( "pointsize", mitk::FloatProperty::New( 0.3) ); pointSetNode->SetColor( 1.0, 1.0, 1.0 ); GetDefaultDataStorage()->Add(pointSetNode); } // generate image displaying the fiber endings void QmitkFiberBundleOperationsView::GenerateFiberEndingsImage() { if(m_FiberBundle.IsNull()){ QMessageBox::information( NULL, "Warning", "No fiber bundle selected!"); MITK_WARN("QmitkGlobalFiberTrackingView") << "no fiber bundle selected"; return; } typedef unsigned char OutPixType; // run generator typedef itk::TractsToFiberEndingsImageFilter ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(m_FiberBundle); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); generator->Update(); // get result typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // to datastorage mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); QString name(m_FiberBundleNode->GetName().c_str()); name += "_fiber_endings"; node->SetName(name.toStdString()); node->SetVisibility(true); GetDataStorage()->Add(node); } // generate rgba heatmap from fiber bundle void QmitkFiberBundleOperationsView::GenerateColorHeatmap() { if(m_FiberBundle.IsNull() || m_FiberBundleNode.IsNull()) { QMessageBox::information( NULL, "Warning", "No fiber bundle selected!"); MITK_WARN("QmitkGlobalFiberTrackingView") << "no fiber bundle selected"; return; } typedef itk::RGBAPixel OutPixType; // run generator typedef itk::TractsToProbabilityImageFilter ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); //generator->SetInput(NULL); generator->SetFiberBundle(m_FiberBundle); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); generator->Update(); // get result typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // to datastorage mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); QString name(m_FiberBundleNode->GetName().c_str()); name += "_rgba_heatmap"; node->SetName(name.toStdString()); node->SetVisibility(true); mitk::LevelWindow opaclevwin; opaclevwin.SetRangeMinMax(0,255); opaclevwin.SetWindowBounds(0,0); mitk::LevelWindowProperty::Pointer prop = mitk::LevelWindowProperty::New(opaclevwin); node->AddProperty( "opaclevelwindow", prop ); GetDataStorage()->Add(node); } // generate greyscale heatmap from fiber bundle void QmitkFiberBundleOperationsView::GenerateGreyscaleHeatmap(bool binary) { if(m_FiberBundle.IsNull() || m_FiberBundleNode.IsNull()) { QMessageBox::information( NULL, "Warning", "No fiber bundle selected!"); MITK_WARN("QmitkGlobalFiberTrackingView") << "no fiber bundle selected"; return; } typedef unsigned char OutPixType; // run generator typedef itk::TractsToProbabilityImageFilter ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(m_FiberBundle); generator->SetInvertImage(m_Controls->m_InvertCheckbox->isChecked()); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (binary) generator->SetBinaryEnvelope(true); else generator->SetBinaryEnvelope(false); generator->Update(); // get result typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // to datastorage mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); QString name(m_FiberBundleNode->GetName().c_str()); if(binary) name += "_enveloppe"; else name += "_heatmap"; node->SetName(name.toStdString()); node->SetVisibility(true); mitk::LevelWindow opaclevwin2; opaclevwin2.SetRangeMinMax(0,255); opaclevwin2.SetWindowBounds(0,0); mitk::LevelWindowProperty::Pointer prop2 = mitk::LevelWindowProperty::New(opaclevwin2); node->AddProperty( "opaclevelwindow", prop2 ); GetDataStorage()->Add(node); } // generate dwi from fiber bundle (experimental) void QmitkFiberBundleOperationsView::DWIGenerationStart() { // get fiber bundle and dwi image from data manager typedef mitk::DiffusionImage DiffVolumesType; std::vector nodes = GetDataManagerSelection(); DiffVolumesType::Pointer originalDWI = NULL; mitk::FiberBundle::Pointer fiberBundle = NULL; for( std::vector::iterator it = nodes.begin(); it != nodes.end(); ++it ) { mitk::DataNode::Pointer node = *it; if (node.IsNotNull() && dynamic_cast(node->GetData())) { originalDWI = dynamic_cast(node->GetData()); continue; } if (node.IsNotNull() && dynamic_cast(node->GetData())) { fiberBundle = dynamic_cast(node->GetData()); } } if(fiberBundle.IsNull() || originalDWI.IsNull()){ QMessageBox::information( NULL, "Warning", "Please load and select a dwi image and a fiber bundle."); MITK_WARN("QmitkGlobalFiberTrackingView") << "please select a fiber bundle and a diffusion image"; return; } // CONSTRUCT CONTAINER WITH DIRECTIONS typedef vnl_vector_fixed< double, 3 > GradientDirectionType; typedef itk::VectorContainer< unsigned int, GradientDirectionType > GradientDirectionContainerType; GradientDirectionContainerType::Pointer directions = originalDWI->GetDirections(); float bVal = originalDWI->GetB_Value(); typedef itk::VectorImage< short, 3 > DWIImageType; DWIImageType::Pointer vectorImage = DWIImageType::New(); itk::TractsToDWIImageFilter::Pointer filter = itk::TractsToDWIImageFilter::New(); filter->SetInput(originalDWI->GetVectorImage()); filter->SetFiberBundle(fiberBundle); filter->SetbD(m_Controls->m_UpsamplingSpinBox->value()); filter->SetGradientDirections(directions); filter->SetParticleWidth(0.2); filter->GenerateData(); vectorImage = filter->GetOutput(); DiffVolumesType::Pointer diffImage = DiffVolumesType::New(); diffImage->SetDirections(directions); diffImage->SetOriginalDirections(directions); diffImage->SetVectorImage(vectorImage); diffImage->SetB_Value(bVal); diffImage->InitializeFromVectorImage(); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( diffImage ); QString name(m_FiberBundleNode->GetName().c_str()); name += "_dwi"; GetDefaultDataStorage()->Add(node); } diff --git a/Modules/Bundles/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberBundleOperationsView.h b/Modules/Bundles/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberBundleOperationsView.h index c82de84190..b63a768740 100644 --- a/Modules/Bundles/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberBundleOperationsView.h +++ b/Modules/Bundles/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberBundleOperationsView.h @@ -1,191 +1,199 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2010-03-31 16:40:27 +0200 (Mi, 31 Mrz 2010) $ Version: $Revision: 21975 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef QmitkFiberBundleOperationsView_h #define QmitkFiberBundleOperationsView_h #include #include #include #include "ui_QmitkFiberBundleOperationsViewControls.h" #include "mitkDataStorage.h" #include "mitkDataStorageSelection.h" #include "mitkPlanarFigure.h" #include "mitkFiberBundle.h" #include "mitkPlanarFigureComposite.h" #include #include #include #include #include #include #include #include #include #include #include +#include +#include +struct FboSelListener; /*! \brief QmitkFiberBundleView \warning This application module is not yet documented. Use "svn blame/praise/annotate" and ask the author to provide basic documentation. \sa QmitkFunctionality \ingroup Functionalities */ class QmitkFiberBundleOperationsView : public QmitkFunctionality { + friend struct FboSelListener; + // 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: typedef itk::Image< unsigned char, 3 > MaskImage3DType; typedef itk::Image< float, 3 > FloatImageType; static const std::string VIEW_ID; QmitkFiberBundleOperationsView(); virtual ~QmitkFiberBundleOperationsView(); virtual void CreateQtPartControl(QWidget *parent); virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget); virtual void StdMultiWidgetNotAvailable(); virtual void Activated(); protected slots: /// \brief Called when the user clicks the GUI button void ActionDrawEllipseTriggered(); void ActionDrawPolygonTriggered(); void DoFiberExtraction(); void generatePFCompo_AND(); void generatePFCompo_OR(); void generatePFCompo_NOT(); void deletePFCompo(); void JoinBundles(); void SubstractBundles(); void GenerateROIImage(); void GenerationStart(); virtual void AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *propertyKey = NULL, mitk::BaseProperty *property = NULL ); protected: /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged( std::vector nodes ); Ui::QmitkFiberBundleOperationsViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; //void Select( mitk::DataNode::Pointer node, bool clearMaskOnFirstArgNULL=false, bool clearImageOnFirstArgNULL=false ); /** Connection from VTK to ITK */ template void ConnectPipelines(VTK_Exporter* exporter, ITK_Importer importer) { importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); importer->SetSpacingCallback(exporter->GetSpacingCallback()); importer->SetOriginCallback(exporter->GetOriginCallback()); importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); importer->SetCallbackUserData(exporter->GetCallbackUserData()); } template void ConnectPipelines(ITK_Exporter exporter, VTK_Importer* importer) { importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); importer->SetSpacingCallback(exporter->GetSpacingCallback()); importer->SetOriginCallback(exporter->GetOriginCallback()); importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); importer->SetCallbackUserData(exporter->GetCallbackUserData()); } template < typename TPixel, unsigned int VImageDimension > void InternalCalculateMaskFromPlanarFigure( itk::Image< TPixel, VImageDimension > *image, unsigned int axis ); template < typename TPixel, unsigned int VImageDimension > void InternalReorientImagePlane( const itk::Image< TPixel, VImageDimension > *image, mitk::Geometry3D* imggeo, mitk::Geometry3D* planegeo3D, int additionalIndex ); + berry::ISelectionListener::Pointer m_SelListener; + berry::IStructuredSelection::ConstPointer m_CurrentSelection; + private: int m_EllipseCounter; int m_PolygonCounter; //contains the selected FiberBundles std::vector m_SelectedFB; //contains the selected PlanarFigures std::vector m_SelectedPF; mitk::Image::ConstPointer m_Image; mitk::Image::Pointer m_InternalImage; mitk::PlanarFigure::Pointer m_PlanarFigure; float m_UpsamplingFactor; MaskImage3DType::Pointer m_InternalImageMask3D; MaskImage3DType::Pointer m_PlanarFigureImage; mitk::FiberBundle::Pointer m_FiberBundle; mitk::DataNode::Pointer m_FiberBundleNode; void addPFCompositionToDataStorage(mitk::PlanarFigureComposite::Pointer, mitk::DataNode::Pointer); void debugPFComposition(mitk::PlanarFigureComposite::Pointer , int ); void CompositeExtraction(mitk::PlanarFigure::Pointer planarFigure, mitk::Image* image); void GenerateGreyscaleHeatmap(bool binary); void GenerateColorHeatmap(); void GenerateFiberEndingsImage(); void GenerateFiberEndingsPointSet(); void DWIGenerationStart(); }; #endif // _QMITKFIBERTRACKINGVIEW_H_INCLUDED diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp index 84b3c9f338..49487f0aa8 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp @@ -1,691 +1,694 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2009-07-08 11:04:08 +0200 (Mi, 08 Jul 2009) $ Version: $Revision: 18029 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkPlanarFigure.h" #include "mitkGeometry2D.h" #include "mitkProperties.h" #include "algorithm" mitk::PlanarFigure::PlanarFigure() : m_FigurePlaced( false ), m_PreviewControlPointVisible( false ), m_SelectedControlPoint( -1 ), m_Geometry2D( NULL ), m_PolyLineUpToDate(false), m_HelperLinesUpToDate(false), m_FeaturesUpToDate(false), m_FeaturesMTime( 0 ) { + + m_HelperPolyLinesToBePainted = BoolContainerType::New(); m_DisplaySize.first = 0.0; m_DisplaySize.second = 0; this->SetProperty( "closed", mitk::BoolProperty::New( false ) ); // Currently only single-time-step geometries are supported this->InitializeTimeSlicedGeometry( 1 ); } mitk::PlanarFigure::~PlanarFigure() { } void mitk::PlanarFigure::SetGeometry2D( mitk::Geometry2D *geometry ) { this->SetGeometry( geometry ); m_Geometry2D = geometry; } const mitk::Geometry2D *mitk::PlanarFigure::GetGeometry2D() const { return m_Geometry2D; } bool mitk::PlanarFigure::IsClosed() const { mitk::BoolProperty* closed = dynamic_cast< mitk::BoolProperty* >( this->GetProperty( "closed" ).GetPointer() ); if ( closed != NULL ) { return closed->GetValue(); } return false; } void mitk::PlanarFigure::PlaceFigure( const mitk::Point2D& point ) { for ( unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i ) { m_ControlPoints.push_back( this->ApplyControlPointConstraints( i, point ) ); } m_FigurePlaced = true; m_SelectedControlPoint = 1; } bool mitk::PlanarFigure::AddControlPoint( const mitk::Point2D& point, int position ) { // if we already have the maximum number of control points, do nothing if ( m_NumberOfControlPoints < this->GetMaximumNumberOfControlPoints() ) { // if position has not been defined or position would be the last control point, just append the new one // we also append a new point if we click onto the line between the first two control-points if the second control-point is selected // -> special case for PlanarCross if ( position == -1 || position > m_NumberOfControlPoints-1 || (position == 1 && m_SelectedControlPoint == 2) ) { if ( m_ControlPoints.size() > this->GetMaximumNumberOfControlPoints()-1 ) { m_ControlPoints.resize( this->GetMaximumNumberOfControlPoints()-1 ); } m_ControlPoints.push_back( this->ApplyControlPointConstraints( m_NumberOfControlPoints, point ) ); m_SelectedControlPoint = m_NumberOfControlPoints; } else { // insert the point at the given position ControlPointListType::iterator iter = m_ControlPoints.begin() + position; m_ControlPoints.insert( iter, this->ApplyControlPointConstraints( position, point ) ); m_SelectedControlPoint = m_NumberOfControlPoints; } // polylines & helperpolylines need to be repainted m_PolyLineUpToDate = false; m_HelperLinesUpToDate = false; m_FeaturesUpToDate = false; // one control point more ++m_NumberOfControlPoints; return true; } else { return false; } } bool mitk::PlanarFigure::SetControlPoint( unsigned int index, const Point2D& point, bool createIfDoesNotExist ) { bool controlPointSetCorrectly = false; if (createIfDoesNotExist) { if ( m_NumberOfControlPoints <= index ) { m_ControlPoints.push_back( this->ApplyControlPointConstraints( index, point ) ); m_NumberOfControlPoints++; } else { m_ControlPoints.at( index ) = this->ApplyControlPointConstraints( index, point ); } controlPointSetCorrectly = true; } else if ( index < m_NumberOfControlPoints ) { m_ControlPoints.at( index ) = this->ApplyControlPointConstraints( index, point ); controlPointSetCorrectly = true; } else { return false; } if ( controlPointSetCorrectly ) { m_PolyLineUpToDate = false; m_HelperLinesUpToDate = false; m_FeaturesUpToDate = false; } return controlPointSetCorrectly; } bool mitk::PlanarFigure::SetCurrentControlPoint( const Point2D& point ) { if ( (m_SelectedControlPoint < 0) || (m_SelectedControlPoint >= (int)m_NumberOfControlPoints) ) { return false; } return this->SetControlPoint(m_SelectedControlPoint, point, false); } unsigned int mitk::PlanarFigure::GetNumberOfControlPoints() const { return m_NumberOfControlPoints; } bool mitk::PlanarFigure::SelectControlPoint( unsigned int index ) { if ( index < this->GetNumberOfControlPoints() ) { m_SelectedControlPoint = index; return true; } else { return false; } } void mitk::PlanarFigure::DeselectControlPoint() { m_SelectedControlPoint = -1; } void mitk::PlanarFigure::SetPreviewControlPoint( const Point2D& point ) { m_PreviewControlPoint = point; m_PreviewControlPointVisible = true; } void mitk::PlanarFigure::ResetPreviewContolPoint() { m_PreviewControlPointVisible = false; } mitk::Point2D mitk::PlanarFigure::GetPreviewControlPoint() { return m_PreviewControlPoint; } bool mitk::PlanarFigure::IsPreviewControlPointVisible() { return m_PreviewControlPointVisible; } mitk::Point2D mitk::PlanarFigure::GetControlPoint( unsigned int index ) const { + int i = m_ControlPoints.size(); if ( index < m_NumberOfControlPoints ) { return m_ControlPoints.at( index ); } itkExceptionMacro( << "GetControlPoint(): Invalid index!" ); } mitk::Point3D mitk::PlanarFigure::GetWorldControlPoint( unsigned int index ) const { Point3D point3D; if ( (m_Geometry2D != NULL) && (index < m_NumberOfControlPoints) ) { m_Geometry2D->Map( m_ControlPoints.at( index ), point3D ); return point3D; } itkExceptionMacro( << "GetWorldControlPoint(): Invalid index!" ); } const mitk::PlanarFigure::PolyLineType mitk::PlanarFigure::GetPolyLine(unsigned int index) { mitk::PlanarFigure::PolyLineType polyLine; if ( m_PolyLines.size() > index || !m_PolyLineUpToDate ) { this->GeneratePolyLine(); m_PolyLineUpToDate = true; } return m_PolyLines.at( index );; } const mitk::PlanarFigure::PolyLineType mitk::PlanarFigure::GetPolyLine(unsigned int index) const { return m_PolyLines.at( index ); } void mitk::PlanarFigure::ClearPolyLines() { for ( int i=0; iGenerateHelperPolyLine(mmPerDisplayUnit, displayHeight); m_HelperLinesUpToDate = true; // store these parameters to be able to check next time if somebody zoomed in or out m_DisplaySize.first = mmPerDisplayUnit; m_DisplaySize.second = displayHeight; } helperPolyLine = m_HelperPolyLines.at(index); } return helperPolyLine; } void mitk::PlanarFigure::ClearHelperPolyLines() { for ( int i=0; iGeneratePolyLine(); } this->EvaluateFeaturesInternal(); m_FeaturesUpToDate = true; } } void mitk::PlanarFigure::UpdateOutputInformation() { // Bounds are NOT calculated here, since the Geometry2D defines a fixed // frame (= bounds) for the planar figure. Superclass::UpdateOutputInformation(); this->GetTimeSlicedGeometry()->UpdateInformation(); } void mitk::PlanarFigure::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::PlanarFigure::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::PlanarFigure::VerifyRequestedRegion() { return true; } void mitk::PlanarFigure::SetRequestedRegion( itk::DataObject * /*data*/ ) { } void mitk::PlanarFigure::ResetNumberOfControlPoints( int numberOfControlPoints ) { m_NumberOfControlPoints = numberOfControlPoints; } mitk::Point2D mitk::PlanarFigure::ApplyControlPointConstraints( unsigned int /*index*/, const Point2D& point ) { if ( m_Geometry2D == NULL ) { return point; } Point2D indexPoint; m_Geometry2D->WorldToIndex( point, indexPoint ); BoundingBox::BoundsArrayType bounds = m_Geometry2D->GetBounds(); if ( indexPoint[0] < bounds[0] ) { indexPoint[0] = bounds[0]; } if ( indexPoint[0] > bounds[1] ) { indexPoint[0] = bounds[1]; } if ( indexPoint[1] < bounds[2] ) { indexPoint[1] = bounds[2]; } if ( indexPoint[1] > bounds[3] ) { indexPoint[1] = bounds[3]; } Point2D constrainedPoint; m_Geometry2D->IndexToWorld( indexPoint, constrainedPoint ); return constrainedPoint; } unsigned int mitk::PlanarFigure::AddFeature( const char *featureName, const char *unitName ) { unsigned int index = m_Features.size(); Feature newFeature( featureName, unitName ); m_Features.push_back( newFeature ); return index; } void mitk::PlanarFigure::SetFeatureName( unsigned int index, const char *featureName ) { if ( index < m_Features.size() ) { m_Features[index].Name = featureName; } } void mitk::PlanarFigure::SetFeatureUnit( unsigned int index, const char *unitName ) { if ( index < m_Features.size() ) { m_Features[index].Unit = unitName; } } void mitk::PlanarFigure::SetQuantity( unsigned int index, double quantity ) { if ( index < m_Features.size() ) { m_Features[index].Quantity = quantity; } } void mitk::PlanarFigure::ActivateFeature( unsigned int index ) { if ( index < m_Features.size() ) { m_Features[index].Active = true; } } void mitk::PlanarFigure::DeactivateFeature( unsigned int index ) { if ( index < m_Features.size() ) { m_Features[index].Active = false; } } void mitk::PlanarFigure::InitializeTimeSlicedGeometry( unsigned int timeSteps ) { mitk::TimeSlicedGeometry::Pointer timeGeometry = this->GetTimeSlicedGeometry(); mitk::Geometry2D::Pointer geometry2D = mitk::Geometry2D::New(); geometry2D->Initialize(); if ( timeSteps > 1 ) { mitk::ScalarType timeBounds[] = {0.0, 1.0}; geometry2D->SetTimeBounds( timeBounds ); } // The geometry is propagated automatically to all time steps, // if EvenlyTimed is true... timeGeometry->InitializeEvenlyTimed( geometry2D, timeSteps ); } void mitk::PlanarFigure::PrintSelf( std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf( os, indent ); os << indent << this->GetNameOfClass() << ":\n"; if (this->IsClosed()) os << indent << "This figure is closed\n"; else os << indent << "This figure is not closed\n"; os << indent << "Minimum number of control points: " << this->GetMinimumNumberOfControlPoints() << std::endl; os << indent << "Maximum number of control points: " << this->GetMaximumNumberOfControlPoints() << std::endl; os << indent << "Current number of control points: " << this->GetNumberOfControlPoints() << std::endl; os << indent << "Control points:" << std::endl; for ( unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i ) { //os << indent.GetNextIndent() << i << ": " << m_ControlPoints->ElementAt( i ) << std::endl; os << indent.GetNextIndent() << i << ": " << m_ControlPoints.at( i ) << std::endl; } os << indent << "Geometry:\n"; this->GetGeometry2D()->Print(os, indent.GetNextIndent()); } unsigned short mitk::PlanarFigure::GetPolyLinesSize() { if ( !m_PolyLineUpToDate ) { this->GeneratePolyLine(); m_PolyLineUpToDate = true; } return m_PolyLines.size(); } unsigned short mitk::PlanarFigure::GetHelperPolyLinesSize() { return m_HelperPolyLines.size(); } bool mitk::PlanarFigure::IsHelperToBePainted(unsigned int index) { return m_HelperPolyLinesToBePainted->GetElement( index ); } bool mitk::PlanarFigure::ResetOnPointSelect() { return false; } void mitk::PlanarFigure::RemoveControlPoint( unsigned int index ) { if ( index > m_ControlPoints.size() ) return; if ( (m_ControlPoints.size() -1) < this->GetMinimumNumberOfControlPoints() ) return; ControlPointListType::iterator iter; iter = m_ControlPoints.begin() + index; m_ControlPoints.erase( iter ); m_PolyLineUpToDate = false; m_HelperLinesUpToDate = false; m_FeaturesUpToDate = false; --m_NumberOfControlPoints; } void mitk::PlanarFigure::RemoveLastControlPoint() { RemoveControlPoint( m_ControlPoints.size()-1 ); } void mitk::PlanarFigure::DeepCopy(Self::Pointer oldFigure) { //DeepCopy only same types of planar figures //Notice to get typeid polymorph you have to use the *operator if(typeid(*oldFigure) != typeid(*this)) { itkExceptionMacro( << "DeepCopy(): Inconsistent type of source (" << typeid(*oldFigure).name() << ") and destination figure (" << typeid(*this).name() << ")!" ); return; } m_ControlPoints.clear(); this->ClearPolyLines(); this->ClearHelperPolyLines(); // clone base data members SetPropertyList(oldFigure->GetPropertyList()->Clone()); /// deep copy members m_FigurePlaced = oldFigure->m_FigurePlaced; m_SelectedControlPoint = oldFigure->m_SelectedControlPoint; m_FeaturesMTime = oldFigure->m_FeaturesMTime; m_Features = oldFigure->m_Features; m_NumberOfControlPoints = oldFigure->m_NumberOfControlPoints; //copy geometry 2D of planar figure SetGeometry2D((mitk::Geometry2D*)oldFigure->m_Geometry2D->Clone().GetPointer()); for(unsigned long index=0; index < oldFigure->GetNumberOfControlPoints(); index++) { m_ControlPoints.push_back( oldFigure->GetControlPoint( index )); } //After setting the control points we can generate the polylines this->GeneratePolyLine(); } void mitk::PlanarFigure::SetNumberOfPolyLines( unsigned int numberOfPolyLines ) { m_PolyLines.resize(numberOfPolyLines); } void mitk::PlanarFigure::SetNumberOfHelperPolyLines( unsigned int numberOfHerlperPolyLines ) { m_HelperPolyLines.resize(numberOfHerlperPolyLines); } void mitk::PlanarFigure::AppendPointToPolyLine( unsigned int index, PolyLineElement element ) { if ( index < m_PolyLines.size() ) { m_PolyLines.at( index ).push_back( element ); } else { MITK_ERROR << "Tried to add point to PolyLine " << index+1 << ", although only " << m_PolyLines.size() << " exists"; } } void mitk::PlanarFigure::AppendPointToHelperPolyLine( unsigned int index, PolyLineElement element ) { if ( index < m_HelperPolyLines.size() ) { m_HelperPolyLines.at( index ).push_back( element ); } else { MITK_ERROR << "Tried to add point to HelperPolyLine " << index+1 << ", although only " << m_HelperPolyLines.size() << " exists"; } } diff --git a/Modules/PlanarFigure/Interactions/mitkPlanarFigureInteractor.cpp b/Modules/PlanarFigure/Interactions/mitkPlanarFigureInteractor.cpp index 88c9fcd904..0610d7a1bb 100644 --- a/Modules/PlanarFigure/Interactions/mitkPlanarFigureInteractor.cpp +++ b/Modules/PlanarFigure/Interactions/mitkPlanarFigureInteractor.cpp @@ -1,934 +1,938 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2008-10-02 16:21:08 +0200 (Do, 02 Okt 2008) $ Version: $Revision: 13129 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkPlanarFigureInteractor.h" #include "mitkPointOperation.h" #include "mitkPositionEvent.h" #include "mitkPlanarFigure.h" #include "mitkStatusBar.h" #include "mitkDataNode.h" #include "mitkInteractionConst.h" #include "mitkAction.h" #include "mitkStateEvent.h" #include "mitkOperationEvent.h" #include "mitkUndoController.h" #include "mitkStateMachineFactory.h" #include "mitkStateTransitionOperation.h" #include "mitkBaseRenderer.h" #include "mitkRenderingManager.h" #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateOr.h" //how precise must the user pick the point //default value mitk::PlanarFigureInteractor ::PlanarFigureInteractor(const char * type, DataNode* dataNode, int /* n */ ) : Interactor( type, dataNode ), m_Precision( 6.5 ), m_IsHovering( false ) { } mitk::PlanarFigureInteractor::~PlanarFigureInteractor() { } void mitk::PlanarFigureInteractor::SetPrecision( mitk::ScalarType precision ) { m_Precision = precision; } // Overwritten since this class can handle it better! float mitk::PlanarFigureInteractor ::CanHandleEvent(StateEvent const* stateEvent) const { float returnValue = 0.5; // If it is a key event that can be handled in the current state, // then return 0.5 mitk::DisplayPositionEvent const *disPosEvent = dynamic_cast (stateEvent->GetEvent()); // Key event handling: if (disPosEvent == NULL) { // Check if the current state has a transition waiting for that key event. if (this->GetCurrentState()->GetTransition(stateEvent->GetId())!=NULL) { return 0.5; } else { return 0.0; } } mitk::PlanarFigure *planarFigure = dynamic_cast( m_DataNode->GetData() ); if ( planarFigure != NULL ) { // Give higher priority if this figure is currently selected if ( planarFigure->GetSelectedControlPoint() >= 0 ) { return 1.0; } } return returnValue; } bool mitk::PlanarFigureInteractor ::ExecuteAction( Action *action, mitk::StateEvent const *stateEvent ) { bool ok = false; // Check corresponding data; has to be sub-class of mitk::PlanarFigure mitk::PlanarFigure *planarFigure = dynamic_cast< mitk::PlanarFigure * >( m_DataNode->GetData() ); if ( planarFigure == NULL ) { return false; } // Get the timestep to also support 3D+t const mitk::Event *theEvent = stateEvent->GetEvent(); int timeStep = 0; mitk::ScalarType timeInMS = 0.0; if ( theEvent ) { if (theEvent->GetSender() != NULL) { timeStep = theEvent->GetSender()->GetTimeStep( planarFigure ); timeInMS = theEvent->GetSender()->GetTime(); } } // Get Geometry2D of PlanarFigure mitk::Geometry2D *planarFigureGeometry = dynamic_cast< mitk::Geometry2D * >( planarFigure->GetGeometry( timeStep ) ); // Get the Geometry2D of the window the user interacts with (for 2D point // projection) mitk::BaseRenderer *renderer = NULL; const Geometry2D *projectionPlane = NULL; if ( theEvent ) { renderer = theEvent->GetSender(); projectionPlane = renderer->GetCurrentWorldGeometry2D(); } // TODO: Check if display and PlanarFigure geometries are parallel (if they are PlaneGeometries) + switch (action->GetActionId()) { case AcDONOTHING: ok = true; break; case AcCHECKOBJECT: { if ( planarFigure->IsPlaced() ) { this->HandleEvent( new mitk::StateEvent( EIDYES, NULL ) ); } else { this->HandleEvent( new mitk::StateEvent( EIDNO, NULL ) ); } ok = false; break; } case AcADD: - { + { // Invoke event to notify listeners that placement of this PF starts now planarFigure->InvokeEvent( StartPlacementPlanarFigureEvent() ); // Use Geometry2D of the renderer clicked on for this PlanarFigure mitk::PlaneGeometry *planeGeometry = const_cast< mitk::PlaneGeometry * >( dynamic_cast< const mitk::PlaneGeometry * >( renderer->GetSliceNavigationController()->GetCurrentPlaneGeometry() ) ); if ( planeGeometry != NULL ) { planarFigureGeometry = planeGeometry; planarFigure->SetGeometry2D( planeGeometry ); } else { ok = false; break; } // Extract point in 2D world coordinates (relative to Geometry2D of // PlanarFigure) Point2D point2D; if ( !this->TransformPositionEventToPoint2D( stateEvent, point2D, planarFigureGeometry ) ) { ok = false; break; } // Place PlanarFigure at this point planarFigure->PlaceFigure( point2D ); // Re-evaluate features planarFigure->EvaluateFeatures(); //this->LogPrintPlanarFigureQuantities( planarFigure ); // Set a bool property indicating that the figure has been placed in // the current RenderWindow. This is required so that the same render // window can be re-aligned to the Geometry2D of the PlanarFigure later // on in an application. m_DataNode->SetBoolProperty( "PlanarFigureInitializedWindow", true, renderer ); // Update rendered scene renderer->GetRenderingManager()->RequestUpdateAll(); ok = true; break; } case AcMOVEPOINT: { bool isEditable = true; m_DataNode->GetBoolProperty( "planarfigure.iseditable", isEditable ); // Extract point in 2D world coordinates (relative to Geometry2D of // PlanarFigure) Point2D point2D; if ( !this->TransformPositionEventToPoint2D( stateEvent, point2D, planarFigureGeometry ) || !isEditable ) { ok = false; break; } // Move current control point to this point planarFigure->SetCurrentControlPoint( point2D ); // Re-evaluate features planarFigure->EvaluateFeatures(); //this->LogPrintPlanarFigureQuantities( planarFigure ); // Update rendered scene renderer->GetRenderingManager()->RequestUpdateAll(); ok = true; break; } case AcCHECKNMINUS1: { if ( planarFigure->GetNumberOfControlPoints() >= planarFigure->GetMaximumNumberOfControlPoints() ) { // Initial placement finished: deselect control point and send an // event to notify application listeners planarFigure->Modified(); planarFigure->DeselectControlPoint(); planarFigure->InvokeEvent( EndPlacementPlanarFigureEvent() ); planarFigure->InvokeEvent( EndInteractionPlanarFigureEvent() ); planarFigure->SetProperty( "initiallyplaced", mitk::BoolProperty::New( true ) ); m_DataNode->Modified(); this->HandleEvent( new mitk::StateEvent( EIDYES, stateEvent->GetEvent() ) ); } else { this->HandleEvent( new mitk::StateEvent( EIDNO, stateEvent->GetEvent() ) ); } // Update rendered scene renderer->GetRenderingManager()->RequestUpdateAll(); ok = true; break; } case AcCHECKEQUALS1: { // NOTE: Action name is a bit misleading; this action checks whether // the figure has already the minimum number of required points to // be finished. const mitk::PositionEvent *positionEvent = dynamic_cast< const mitk::PositionEvent * > ( stateEvent->GetEvent() ); if ( positionEvent == NULL ) { ok = false; break; } bool tooClose = !IsMousePositionAcceptableAsNewControlPoint( positionEvent, planarFigure ); if ( planarFigure->GetNumberOfControlPoints() >= planarFigure->GetMinimumNumberOfControlPoints() && !tooClose ) { // Initial placement finished: deselect control point and send an // event to notify application listeners planarFigure->Modified(); planarFigure->DeselectControlPoint(); if ( planarFigure->GetNumberOfControlPoints()-1 >= planarFigure->GetMinimumNumberOfControlPoints() ) { planarFigure->RemoveLastControlPoint(); } planarFigure->InvokeEvent( EndPlacementPlanarFigureEvent() ); planarFigure->InvokeEvent( EndInteractionPlanarFigureEvent() ); planarFigure->SetProperty( "initiallyplaced", mitk::BoolProperty::New( true ) ); m_DataNode->Modified(); this->HandleEvent( new mitk::StateEvent( EIDYES, NULL ) ); } else { this->HandleEvent( new mitk::StateEvent( EIDNO, NULL ) ); } // Update rendered scene renderer->GetRenderingManager()->RequestUpdateAll(); ok = true; break; } case AcCHECKPOINT: { // Check if the distance of the current point to the previously set point in display coordinates // is sufficient (if a previous point exists) // Extract display position - const mitk::PositionEvent *positionEvent = + const mitk::PositionEvent *positionEvent = dynamic_cast< const mitk::PositionEvent * > ( stateEvent->GetEvent() ); if ( positionEvent == NULL ) { ok = false; break; } bool tooClose = !IsMousePositionAcceptableAsNewControlPoint( positionEvent, planarFigure ); if (tooClose) { this->HandleEvent( new mitk::StateEvent( EIDNO, stateEvent->GetEvent() ) ); } else { this->HandleEvent( new mitk::StateEvent( EIDYES, stateEvent->GetEvent() ) ); } ok = true; break; } case AcADDPOINT: { - bool selected = false; + bool selected = false; bool isEditable = true; m_DataNode->GetBoolProperty("selected", selected); m_DataNode->GetBoolProperty( "planarfigure.iseditable", isEditable ); if ( !selected || !isEditable ) { ok = false; break; } // Extract point in 2D world coordinates (relative to Geometry2D of // PlanarFigure) Point2D point2D, projectedPoint; if ( !this->TransformPositionEventToPoint2D( stateEvent, point2D, planarFigureGeometry ) ) { ok = false; break; } // TODO: check segement of polyline we clicked in int nextIndex = this->IsPositionOverFigure( stateEvent, planarFigure, planarFigureGeometry, projectionPlane, renderer->GetDisplayGeometry(), projectedPoint ); // Add point as new control point renderer->GetDisplayGeometry()->DisplayToWorld( projectedPoint, projectedPoint ); - + if ( planarFigure->IsPreviewControlPointVisible() ) { point2D = planarFigure->GetPreviewControlPoint(); } planarFigure->AddControlPoint( point2D, nextIndex ); if ( planarFigure->IsPreviewControlPointVisible() ) { planarFigure->SelectControlPoint( nextIndex ); planarFigure->ResetPreviewContolPoint(); } // Re-evaluate features planarFigure->EvaluateFeatures(); //this->LogPrintPlanarFigureQuantities( planarFigure ); // Update rendered scene renderer->GetRenderingManager()->RequestUpdateAll(); ok = true; break; } case AcDESELECTPOINT: { planarFigure->DeselectControlPoint(); // Issue event so that listeners may update themselves planarFigure->Modified(); planarFigure->InvokeEvent( EndInteractionPlanarFigureEvent() ); m_DataNode->Modified(); // falls through } case AcCHECKHOVERING: { mitk::Point2D pointProjectedOntoLine; int previousControlPoint = mitk::PlanarFigureInteractor::IsPositionOverFigure( stateEvent, planarFigure, planarFigureGeometry, projectionPlane, renderer->GetDisplayGeometry(), pointProjectedOntoLine ); bool isHovering = ( previousControlPoint != -1 ); int pointIndex = mitk::PlanarFigureInteractor::IsPositionInsideMarker( stateEvent, planarFigure, planarFigureGeometry, projectionPlane, renderer->GetDisplayGeometry() ); int initiallySelectedControlPoint = planarFigure->GetSelectedControlPoint(); if ( pointIndex >= 0 ) { // If mouse is above control point, mark it as selected - planarFigure->SelectControlPoint( pointIndex ); + planarFigure->SelectControlPoint( pointIndex ); // If mouse is hovering above a marker, it is also hovering above the figure isHovering = true; } else { // Mouse in not above control point --> deselect point planarFigure->DeselectControlPoint(); } bool renderingUpdateNeeded = true; if ( isHovering ) { if ( !m_IsHovering ) { // Invoke hover event once when the mouse is entering the figure area m_IsHovering = true; planarFigure->InvokeEvent( StartHoverPlanarFigureEvent() ); // Set bool property to indicate that planar figure is currently in "hovering" mode m_DataNode->SetBoolProperty( "planarfigure.ishovering", true ); renderingUpdateNeeded = true; } bool selected = false; bool isExtendable = false; bool isEditable = true; m_DataNode->GetBoolProperty("selected", selected); m_DataNode->GetBoolProperty("planarfigure.isextendable", isExtendable); m_DataNode->GetBoolProperty( "planarfigure.iseditable", isEditable ); if ( selected && isHovering && isExtendable && pointIndex == -1 && isEditable ) { - const mitk::PositionEvent *positionEvent = + const mitk::PositionEvent *positionEvent = dynamic_cast< const mitk::PositionEvent * > ( stateEvent->GetEvent() ); if ( positionEvent != NULL ) { renderer->GetDisplayGeometry()->DisplayToWorld( pointProjectedOntoLine, pointProjectedOntoLine ); planarFigure->SetPreviewControlPoint( pointProjectedOntoLine ); renderingUpdateNeeded = true; } } else { planarFigure->ResetPreviewContolPoint(); } if ( planarFigure->GetSelectedControlPoint() != initiallySelectedControlPoint ) { // the selected control point has changed -> rendering update necessary renderingUpdateNeeded = true; } this->HandleEvent( new mitk::StateEvent( EIDYES, stateEvent->GetEvent() ) ); // Return true: only this interactor is eligible to react on this event ok = true; } else { if ( m_IsHovering ) { planarFigure->ResetPreviewContolPoint(); // Invoke end-hover event once the mouse is exiting the figure area m_IsHovering = false; planarFigure->InvokeEvent( EndHoverPlanarFigureEvent() ); // Set bool property to indicate that planar figure is no longer in "hovering" mode m_DataNode->SetBoolProperty( "planarfigure.ishovering", false ); renderingUpdateNeeded = true; } this->HandleEvent( new mitk::StateEvent( EIDNO, NULL ) ); // Return false so that other (PlanarFigure) Interactors may react on this // event as well ok = false; } // Update rendered scene if necessray if ( renderingUpdateNeeded ) { renderer->GetRenderingManager()->RequestUpdateAll(); } break; } case AcCHECKSELECTED: { bool selected = false; m_DataNode->GetBoolProperty("selected", selected); if ( selected ) { this->HandleEvent( new mitk::StateEvent( EIDYES, stateEvent->GetEvent() ) ); } else { // Invoke event to notify listeners that this planar figure should be selected planarFigure->InvokeEvent( SelectPlanarFigureEvent() ); this->HandleEvent( new mitk::StateEvent( EIDNO, NULL ) ); } } case AcSELECTPICKEDOBJECT: { //// Invoke event to notify listeners that this planar figure should be selected //planarFigure->InvokeEvent( SelectPlanarFigureEvent() ); // Check if planar figure is marked as "editable" bool isEditable = true; m_DataNode->GetBoolProperty( "planarfigure.iseditable", isEditable ); int pointIndex = -1; if ( isEditable ) { // If planar figure is editable, check if mouse is over a control point pointIndex = mitk::PlanarFigureInteractor::IsPositionInsideMarker( stateEvent, planarFigure, planarFigureGeometry, projectionPlane, renderer->GetDisplayGeometry() ); } // If editing is enabled and the mouse is currently over a control point, select it if ( pointIndex >= 0 ) { this->HandleEvent( new mitk::StateEvent( EIDYES, stateEvent->GetEvent() ) ); // Return true: only this interactor is eligible to react on this event ok = true; } else { this->HandleEvent( new mitk::StateEvent( EIDNO, stateEvent->GetEvent() ) ); // Return false so that other (PlanarFigure) Interactors may react on this // event as well ok = false; } - ok = true; + ok = true; break; } case AcSELECTPOINT: { // Invoke event to notify listeners that interaction with this PF starts now planarFigure->InvokeEvent( StartInteractionPlanarFigureEvent() ); // Reset the PlanarFigure if required if ( planarFigure->ResetOnPointSelect() ) { this->HandleEvent( new mitk::StateEvent( EIDYES, stateEvent->GetEvent() ) ); } else { this->HandleEvent( new mitk::StateEvent( EIDNO, stateEvent->GetEvent() ) ); } - ok = true; + ok = true; break; } case AcREMOVEPOINT: { bool isExtendable = false; m_DataNode->GetBoolProperty("planarfigure.isextendable", isExtendable); - + if ( isExtendable ) { int selectedControlPoint = planarFigure->GetSelectedControlPoint(); planarFigure->RemoveControlPoint( selectedControlPoint ); // Re-evaluate features planarFigure->EvaluateFeatures(); planarFigure->Modified(); planarFigure->InvokeEvent( EndInteractionPlanarFigureEvent() ); renderer->GetRenderingManager()->RequestUpdateAll(); this->HandleEvent( new mitk::StateEvent( EIDYES, NULL ) ); } else { this->HandleEvent( new mitk::StateEvent( EIDNO, NULL ) ); } } //case AcMOVEPOINT: //case AcMOVESELECTED: // { // // Update the display // renderer->GetRenderingManager()->RequestUpdateAll(); // ok = true; // break; // } //case AcFINISHMOVE: // { // ok = true; // break; // } default: return Superclass::ExecuteAction( action, stateEvent ); } + + + return ok; } bool mitk::PlanarFigureInteractor::TransformPositionEventToPoint2D( const StateEvent *stateEvent, Point2D &point2D, const Geometry2D *planarFigureGeometry ) { // Extract world position, and from this position on geometry, if // available const mitk::PositionEvent *positionEvent = dynamic_cast< const mitk::PositionEvent * > ( stateEvent->GetEvent() ); if ( positionEvent == NULL ) { return false; } mitk::Point3D worldPoint3D = positionEvent->GetWorldPosition(); // TODO: proper handling of distance tolerance if ( planarFigureGeometry->Distance( worldPoint3D ) > 0.1 ) { return false; } // Project point onto plane of this PlanarFigure planarFigureGeometry->Map( worldPoint3D, point2D ); return true; } bool mitk::PlanarFigureInteractor::TransformObjectToDisplay( const mitk::Point2D &point2D, mitk::Point2D &displayPoint, const mitk::Geometry2D *objectGeometry, const mitk::Geometry2D *rendererGeometry, const mitk::DisplayGeometry *displayGeometry ) const { mitk::Point3D point3D; // Map circle point from local 2D geometry into 3D world space objectGeometry->Map( point2D, point3D ); // TODO: proper handling of distance tolerance if ( displayGeometry->Distance( point3D ) < 0.1 ) { // Project 3D world point onto display geometry rendererGeometry->Map( point3D, displayPoint ); displayGeometry->WorldToDisplay( displayPoint, displayPoint ); return true; } return false; } bool mitk::PlanarFigureInteractor::IsPointNearLine( const mitk::Point2D& point, const mitk::Point2D& startPoint, const mitk::Point2D& endPoint, mitk::Point2D& projectedPoint ) const { mitk::Vector2D n1 = endPoint - startPoint; n1.Normalize(); // Determine dot products between line vector and startpoint-point / endpoint-point vectors double l1 = n1 * (point - startPoint); double l2 = -n1 * (point - endPoint); // Determine projection of specified point onto line defined by start / end point mitk::Point2D crossPoint = startPoint + n1 * l1; projectedPoint = crossPoint; // Point is inside encompassing rectangle IF // - its distance to its projected point is small enough // - it is not further outside of the line than the defined tolerance if ( (crossPoint.SquaredEuclideanDistanceTo( point ) < 20.0 ) && ( l1 > 0.0 ) && ( l2 > 0.0 ) || endPoint.SquaredEuclideanDistanceTo( point ) < 20.0 || startPoint.SquaredEuclideanDistanceTo( point ) < 20.0 ) { return true; } return false; } int mitk::PlanarFigureInteractor::IsPositionOverFigure( const StateEvent *stateEvent, PlanarFigure *planarFigure, const Geometry2D *planarFigureGeometry, const Geometry2D *rendererGeometry, const DisplayGeometry *displayGeometry, Point2D& pointProjectedOntoLine ) const { // Extract display position const mitk::PositionEvent *positionEvent = dynamic_cast< const mitk::PositionEvent * > ( stateEvent->GetEvent() ); if ( positionEvent == NULL ) { return -1; } mitk::Point2D displayPosition = positionEvent->GetDisplayPosition(); // Iterate over all polylines of planar figure, and check if // any one is close to the current display position typedef mitk::PlanarFigure::PolyLineType VertexContainerType; mitk::Point2D worldPoint2D, displayControlPoint; mitk::Point3D worldPoint3D; int previousControlPoint = -1; for ( unsigned short loop = 0; loop < planarFigure->GetPolyLinesSize(); ++loop ) { const VertexContainerType polyLine = planarFigure->GetPolyLine( loop ); Point2D polyLinePoint; Point2D firstPolyLinePoint; Point2D previousPolyLinePoint; bool firstPoint = true; for ( VertexContainerType::const_iterator it = polyLine.begin(); it != polyLine.end(); ++it ) { // Get plane coordinates of this point of polyline (if possible) if ( !this->TransformObjectToDisplay( it->Point, polyLinePoint, planarFigureGeometry, rendererGeometry, displayGeometry ) ) { break; // Poly line invalid (not on current 2D plane) --> skip it } if ( firstPoint ) { firstPolyLinePoint = polyLinePoint; firstPoint = false; } else if ( this->IsPointNearLine( displayPosition, previousPolyLinePoint, polyLinePoint, pointProjectedOntoLine ) ) { // Point is close enough to line segment --> Return index of the segment return it->Index; } previousPolyLinePoint = polyLinePoint; } // For closed figures, also check last line segment if ( planarFigure->IsClosed() && this->IsPointNearLine( displayPosition, polyLinePoint, firstPolyLinePoint, pointProjectedOntoLine ) ) { return 0; // Return index of first control point } } return -1; } int mitk::PlanarFigureInteractor::IsPositionInsideMarker( const StateEvent *stateEvent, const PlanarFigure *planarFigure, const Geometry2D *planarFigureGeometry, const Geometry2D *rendererGeometry, const DisplayGeometry *displayGeometry ) const { // Extract display position const mitk::PositionEvent *positionEvent = dynamic_cast< const mitk::PositionEvent * > ( stateEvent->GetEvent() ); if ( positionEvent == NULL ) { return -1; } mitk::Point2D displayPosition = positionEvent->GetDisplayPosition(); // Iterate over all control points of planar figure, and check if // any one is close to the current display position mitk::Point2D worldPoint2D, displayControlPoint; mitk::Point3D worldPoint3D; int numberOfControlPoints = planarFigure->GetNumberOfControlPoints(); for ( int i=0; iTransformObjectToDisplay( planarFigure->GetControlPoint(i), displayControlPoint, planarFigureGeometry, rendererGeometry, displayGeometry ) ) { // TODO: variable size of markers if ( displayPosition.SquaredEuclideanDistanceTo( displayControlPoint ) < 20.0 ) { return i; } } } //for ( it = controlPoints.begin(); it != controlPoints.end(); ++it ) //{ // Point2D displayControlPoint; // if ( this->TransformObjectToDisplay( it->Point, displayControlPoint, // planarFigureGeometry, rendererGeometry, displayGeometry ) ) // { // // TODO: variable size of markers // if ( (abs(displayPosition[0] - displayControlPoint[0]) < 4 ) // && (abs(displayPosition[1] - displayControlPoint[1]) < 4 ) ) // { // return index; // } // } //} return -1; } void mitk::PlanarFigureInteractor::LogPrintPlanarFigureQuantities( const PlanarFigure *planarFigure ) { MITK_INFO << "PlanarFigure: " << planarFigure->GetNameOfClass(); for ( unsigned int i = 0; i < planarFigure->GetNumberOfFeatures(); ++i ) { MITK_INFO << "* " << planarFigure->GetFeatureName( i ) << ": " << planarFigure->GetQuantity( i ) << " " << planarFigure->GetFeatureUnit( i ); } } bool mitk::PlanarFigureInteractor::IsMousePositionAcceptableAsNewControlPoint( const PositionEvent* positionEvent, const PlanarFigure* planarFigure ) { assert(positionEvent && planarFigure); BaseRenderer* renderer = positionEvent->GetSender(); assert(renderer); // Get the timestep to support 3D+t int timeStep( renderer->GetTimeStep( planarFigure ) ); // Get current display position of the mouse Point2D currentDisplayPosition = positionEvent->GetDisplayPosition(); // Check if a previous point has been set bool tooClose = false; for( int i=0; iGetNumberOfControlPoints() - 1; i++ ) { if ( i != planarFigure->GetSelectedControlPoint()-1 ) { // Try to convert previous point to current display coordinates mitk::Geometry2D *planarFigureGeometry = dynamic_cast< mitk::Geometry2D * >( planarFigure->GetGeometry( timeStep ) ); const Geometry2D *projectionPlane = renderer->GetCurrentWorldGeometry2D(); mitk::Point3D previousPoint3D; planarFigureGeometry->Map( planarFigure->GetControlPoint( i ), previousPoint3D ); if ( renderer->GetDisplayGeometry()->Distance( previousPoint3D ) < 0.1 ) // ugly, but assert makes this work { mitk::Point2D previousDisplayPosition; projectionPlane->Map( previousPoint3D, previousDisplayPosition ); renderer->GetDisplayGeometry()->WorldToDisplay( previousDisplayPosition, previousDisplayPosition ); double a = currentDisplayPosition[0] - previousDisplayPosition[0]; double b = currentDisplayPosition[1] - previousDisplayPosition[1]; // If point is to close, do not set a new point tooClose = (a * a + b * b < 25.0); } if ( tooClose ) return false; // abort loop early } } return !tooClose; // default } diff --git a/Modules/QmitkExt/QmitkPiecewiseFunctionCanvas.cpp b/Modules/QmitkExt/QmitkPiecewiseFunctionCanvas.cpp index c4b364b9cb..42d3ab30cb 100755 --- a/Modules/QmitkExt/QmitkPiecewiseFunctionCanvas.cpp +++ b/Modules/QmitkExt/QmitkPiecewiseFunctionCanvas.cpp @@ -1,157 +1,159 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "QmitkPiecewiseFunctionCanvas.h" #include #include QmitkPiecewiseFunctionCanvas::QmitkPiecewiseFunctionCanvas(QWidget * parent, Qt::WindowFlags f) : QmitkTransferFunctionCanvas(parent, f), m_PiecewiseFunction(0) { // used for drawing a border setContentsMargins(1,1,1,1); } void QmitkPiecewiseFunctionCanvas::SetTitle(const QString& title) { m_Title=title; } void QmitkPiecewiseFunctionCanvas::paintEvent(QPaintEvent*) { QPainter painter(this); PaintHistogram(painter); if (m_Title.size()>0) { painter.setPen(Qt::black); painter.drawText(QPoint(11,21),m_Title); painter.setPen(Qt::white); painter.drawText(QPoint(10,20),m_Title); } { QString qs_min = QString::number( m_Min ); QString qs_max = QString::number( m_Max ); QRect qr_min = painter.fontMetrics().boundingRect( qs_min ); QRect qr_max = painter.fontMetrics().boundingRect( qs_max ); int y,x; y=this->contentsRect().height()-qr_min.height()+5; x=10; + + // Fill the tf presets in the generator widget painter.setPen(Qt::black); painter.drawText(QPoint(x+1,y+1),qs_min); painter.setPen(Qt::white); painter.drawText(QPoint(x ,y ),qs_min); y=this->contentsRect().height()-qr_max.height()+5; x=this->contentsRect().width()-qr_max.width()-6; painter.setPen(Qt::black); painter.drawText(QPoint(x,y+1),qs_max); painter.setPen(Qt::white); painter.drawText(QPoint(x,y ),qs_max); } painter.setPen(Qt::gray); QRect contentsRect = this->contentsRect(); painter.drawRect(0, 0, contentsRect.width()+1, contentsRect.height()+1); if (m_PiecewiseFunction && this->isEnabled()) { vtkFloatingPointType* dp = m_PiecewiseFunction->GetDataPointer(); // Render lines painter.setPen(Qt::black); for (int i = -1; i < m_PiecewiseFunction->GetSize(); i++) { std::pair left; std::pair right; if(i < 0) left = this->FunctionToCanvas(std::make_pair(-32768, dp[0 * 2 + 1])); else left = this->FunctionToCanvas(std::make_pair(dp[i * 2], dp[i * 2 + 1])); if(i+1 >= m_PiecewiseFunction->GetSize()) right = this->FunctionToCanvas(std::make_pair(32768, dp[(i ) * 2 + 1])); else right = this->FunctionToCanvas(std::make_pair(dp[(i+1) * 2], dp[(i+1) * 2 + 1])); painter.drawLine(left.first, left.second, right.first, right.second); } // Render Points for (int i = 0; i < m_PiecewiseFunction->GetSize(); i++) { std::pair point = this->FunctionToCanvas(std::make_pair( dp[i * 2], dp[i * 2 + 1])); if (i == m_GrabbedHandle) { painter.setBrush(QBrush(Qt::red)); if (m_LineEditAvailable) { m_XEdit->setText(QString::number(GetFunctionX(m_GrabbedHandle))); m_YEdit->setText(QString::number(GetFunctionY(m_GrabbedHandle))); } } else { painter.setBrush(QBrush(Qt::green)); } painter.drawEllipse(point.first - 4, point.second - 4, 8, 8); } painter.setBrush(Qt::NoBrush); } } int QmitkPiecewiseFunctionCanvas::GetNearHandle(int x, int y, unsigned int maxSquaredDistance) { vtkFloatingPointType* dp = m_PiecewiseFunction->GetDataPointer(); for (int i = 0; i < m_PiecewiseFunction->GetSize(); i++) { std::pair point = this->FunctionToCanvas(std::make_pair(dp[i * 2], dp[i * 2 + 1])); if ((unsigned int) ((point.first - x) * (point.first - x) + (point.second - y) * (point.second - y)) <= maxSquaredDistance) { return i; } } return -1; } void QmitkPiecewiseFunctionCanvas::MoveFunctionPoint(int index, std::pair pos) { RemoveFunctionPoint(GetFunctionX(index)); AddFunctionPoint(pos.first, pos.second); //std::cout<<" AddFunctionPoint x: "< #include #include "QmitkPlotWidget.h" QmitkPlotWidget::QmitkPlotWidget(QWidget* parent, const char* title, const char* /*name*/, Qt::WindowFlags f): QWidget(parent, f) { QVBoxLayout* boxLayout = new QVBoxLayout(this); m_Plot = new QwtPlot( QwtText(title), this ) ; m_Plot->setCanvasBackground(Qt::white); boxLayout->addWidget( m_Plot ); + + + m_PlotPicker = new QwtPlotPicker(m_Plot->canvas()); + m_PlotPicker->setSelectionFlags(QwtPicker::PointSelection | QwtPicker::ClickSelection); + m_PlotPicker->setTrackerMode(QwtPicker::ActiveOnly); + + connect(m_PlotPicker, SIGNAL(selected(const QwtDoublePoint&)), this, SLOT( Clicked(const QwtDoublePoint&) ) ); + connect(m_PlotPicker, SIGNAL(appended(QwtDoublePoint&)), this, SLOT( Clicked() ) ); + connect(m_PlotPicker, SIGNAL(moved(QwtDoublePoint&)), this, SLOT( Clicked() ) ); } +void QmitkPlotWidget::Clicked(const QwtDoublePoint&) +{ + std::cout << "click"; +} + QmitkPlotWidget::~QmitkPlotWidget() { this->Clear(); delete m_Plot; } QwtPlot* QmitkPlotWidget::GetPlot() { return m_Plot; } void QmitkPlotWidget::SetLegend(QwtLegend* legend, QwtPlot::LegendPosition pos, double ratio) { m_Plot->insertLegend(legend, pos, ratio); } unsigned int QmitkPlotWidget::InsertCurve(const char* title) { QwtPlotCurve* curve = new QwtPlotCurve(QwtText(title)); m_PlotCurveVector.push_back(curve); curve->attach(m_Plot); return static_cast (m_PlotCurveVector.size() - 1); } void QmitkPlotWidget::SetPlotTitle(const char* title) { m_Plot->setTitle(title); } void QmitkPlotWidget::SetAxisTitle(int axis, const char* title) { m_Plot->setAxisTitle(axis, title); } bool QmitkPlotWidget::SetCurveData( unsigned int curveId, const QmitkPlotWidget::DataVector& xValues, const QmitkPlotWidget::DataVector& yValues ) { if ( xValues.size() != yValues.size() ) { std::cerr << "Sizes of data arrays don't match." << std::endl; return false; } double* rawDataX = ConvertToRawArray( xValues ); double* rawDataY = ConvertToRawArray( yValues ); m_PlotCurveVector[curveId]->setData( rawDataX, rawDataY, static_cast(xValues.size()) ); delete[] rawDataX; delete[] rawDataY; return true; } bool QmitkPlotWidget::SetCurveData( unsigned int curveId, const QmitkPlotWidget::XYDataVector& data ) { double* rawDataX = ConvertToRawArray( data, 0 ); double* rawDataY = ConvertToRawArray( data, 1 ); m_PlotCurveVector[curveId]->setData( rawDataX, rawDataY, static_cast(data.size()) ); delete[] rawDataX; delete[] rawDataY; return true; } void QmitkPlotWidget::SetCurvePen( unsigned int curveId, const QPen& pen ) { m_PlotCurveVector[curveId]->setPen( pen ); } void QmitkPlotWidget::SetCurveBrush( unsigned int curveId, const QBrush& brush ) { m_PlotCurveVector[curveId]->setBrush( brush ); } void QmitkPlotWidget::SetCurveTitle( unsigned int /*curveId*/, const char* title ) { m_Plot->setTitle( title ); } void QmitkPlotWidget::SetCurveStyle( unsigned int curveId, const QwtPlotCurve::CurveStyle style ) { m_PlotCurveVector[curveId]->setStyle(style); } void QmitkPlotWidget::SetCurveSymbol( unsigned int curveId, QwtSymbol* symbol ) { m_PlotCurveVector[curveId]->setSymbol(*symbol); } void QmitkPlotWidget::Replot() { m_Plot->replot(); } void QmitkPlotWidget::Clear() { m_PlotCurveVector.clear(); m_PlotCurveVector.resize(0); m_Plot->clear(); } double* QmitkPlotWidget::ConvertToRawArray( const QmitkPlotWidget::DataVector& values ) { double* raw = new double[ values.size() ]; for( unsigned int i = 0; i < values.size(); ++i ) raw[i] = values[i]; return raw; } double* QmitkPlotWidget::ConvertToRawArray( const QmitkPlotWidget::XYDataVector& values, unsigned int component ) { double* raw = new double[ values.size() ]; for( unsigned int i = 0; i < values.size(); ++i ) { switch (component) { case (0): raw[i] = values[i].first; break; case (1): raw[i] = values[i].second; break; default: std::cout << "Component must be either 0 or 1."<< std::endl; } } return raw; } diff --git a/Modules/QmitkExt/QmitkPlotWidget.h b/Modules/QmitkExt/QmitkPlotWidget.h index cd633497c0..777da5872d 100644 --- a/Modules/QmitkExt/QmitkPlotWidget.h +++ b/Modules/QmitkExt/QmitkPlotWidget.h @@ -1,211 +1,221 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef _QmitkPlotWidget_H_ #define _QmitkPlotWidget_H_ #include #include "QmitkExtExports.h" #include #include #include #include "mitkCommon.h" #include #include +#include + /** * Provides a convenient interface for plotting curves using qwt. * Designed for qwt version 5.2.1. * Can be used with a QmitkPlotDialog, which provides a "Close" button. * @see QmitkPlotDialog * * To plot data do the following: * 1. Create two QmitkPlotWidget::DataVector Objects and fill them * with corresponding x/y values. DataVectors are simple stl-vectors * of type std::vector. Please note that the xValues * vector and the yValues vector MUST have the same size. * 2. Instantiate the widget for example like that: * QmitkPlotWidget* widget = new QmitkPlotWidget( this, "widget" ); * widget->SetAxisTitle( QwtPlot::xBottom, "My x asis [mm]" ); * widget->SetAxisTitle( QwtPlot::yLeft, "My y axis [mm]" ); * int curveId = widget->InsertCurve( "My sophisticated data" ); * widget->SetCurveData( curveId, xValues, yValues ); * widget->SetCurvePen( curveId, QPen( red ) ); * widget->SetCurveTitle( curveId, "My curve description" ); * widget->Replot(); * 3. You can modify the behavior of the plot by directly referencing * the QwtPlot instance using the method GetPlot(). * @see QwtPlot */ class QmitkExt_EXPORT QmitkPlotWidget: public QWidget { + Q_OBJECT public: /** * represents the data type used for scalar values stored * in data arrays. This type is provided by qwt and may not * be changed. */ typedef double ScalarType; /** * This type may be used to store a set of scalar values * representing either x or y coordinates of the data * points that should be rendered. */ typedef std::vector DataVector; /** * convenience type used to store pairs representing x/y coordinates * that should be rendered as a curve by the plot widget */ typedef std::vector< std::pair< double, double > > XYDataVector; /** * Standard qt constructor */ QmitkPlotWidget(QWidget* parent = 0,const char* title = 0, const char* name = 0, Qt::WindowFlags f = 0); /** * Virtual destructor */ virtual ~QmitkPlotWidget(); /** * Returns the instance of the plot-widget. This may be used * to modify any detail of the appearance of the plot. */ QwtPlot* GetPlot(); void SetPlotTitle(const char* title); /** * Inserts a new curve into the plot-window. * @param title the name of the curve * @returns the id of the curve. Use this id to * refer to the curve, if you want to modify or add data. */ unsigned int InsertCurve( const char* title ); /** * Sets the title of the given axis. For the set of available axes * @see QwtPlot::Axis. * @param axis the axis for which the description should be set. * @param title the name of the axis. */ void SetAxisTitle(int axis, const char* title); /** * Sets the data for a previously added curve. Data is provided as two vectors of double. * The first vector represents the x coordinates, the second vector represents the y coordinates. * @param curveId the id of the curve for which data should be added. * @param xValues the x coordinates of the points that define the curve * @param yValues the y coordinates of the points that define the curve * @returns whether data was added successfully or not */ bool SetCurveData( unsigned int curveId, const DataVector& xValues, const DataVector& yValues ); /** * Sets the data for a previously added curve. Data is provided as a vectors of pairs. * The pairs represent x/y coordinates of the points that define the curve. * @param curveId the id of the curve for which data should be added. * @param data the coordinates of the points that define the curve * @returns whether data was added successfully or not */ bool SetCurveData( unsigned int curveId, const XYDataVector& data ); /** * Defines how a curve should be drawn. For drawing a curve, a QPen is used. * @param curveId the id of the curve for which appearance should be changed * @param pen a QPen (@see QPen) defining the line style */ void SetCurvePen( unsigned int curveId, const QPen& pen ); /** * Assign a brush, which defines the fill pattern of shapes drawn by a QPainter. * In case of brush.style() != QBrush::NoBrush and * style() != QwtPlotCurve::Sticks * the area between the curve and the baseline will be filled. * In case !brush.color().isValid() the area will be filled by pen.color(). * The fill algorithm simply connects the first and the last curve point to the * baseline. So the curve data has to be sorted (ascending or descending). * @param curveId the id of the curve for which appearance should be changed * @param brush a QBrush (@see QBrush) defining the line style */ void SetCurveBrush( unsigned int curveId, const QBrush& brush); /** * Sets the style how the line is drawn for the curve; like, plain line, * or with the data points marked with a symbol; * @param: style A QwtPlotCurve::CurveStyle */ void SetCurveStyle( unsigned int curveId, const QwtPlotCurve::CurveStyle style ); /** * Sets the style data points are drawn for the curve; like, a line, * or dots; * @param: symbol A QwtSymbol */ void SetCurveSymbol( unsigned int curveId, QwtSymbol* symbol ); /** * Sets the title of the given curve. The title will be shown in the legend of * the QwtPlot. * @param curveId the id of the curve for which the title should be set * @param title the description of the curve that will be shown in the legend. */ void SetCurveTitle( unsigned int curveId, const char* title ); /** * Sets the legend of the plot * */ void SetLegend(QwtLegend* legend, QwtPlot::LegendPosition pos=QwtPlot::RightLegend, double ratio=-1); /** * Triggers a replot of the curve. Replot should be called once after * setting new data. */ void Replot(); /** * Resets the plot into an empty state */ void Clear(); + QwtPlotPicker* m_PlotPicker; + +protected slots: + void Clicked(const QwtDoublePoint&); + protected: /** * Converts the given values into a raw double* array. * A new array is allocated via new and must be deleted[] by the caller. */ double* ConvertToRawArray( const DataVector& values ); /** * Converts the given values into a raw double* array. * A new array is allocated via new and must be deleted[] by the caller. * @param values the x/y values to convert to an array * @param component defines if the x values (0) or the y values(1) should * be converted. Other values than 0 and 1 will not be accepted. */ double* ConvertToRawArray( const XYDataVector& values, unsigned int component ); QwtPlot* m_Plot; std::vector m_PlotCurveVector; + + }; #endif diff --git a/Modules/QmitkExt/files.cmake b/Modules/QmitkExt/files.cmake index 3f117178b0..9ccb0a1fc3 100644 --- a/Modules/QmitkExt/files.cmake +++ b/Modules/QmitkExt/files.cmake @@ -1,253 +1,254 @@ SET(CPP_FILES QmitkApplicationBase/QmitkCommonFunctionality.cpp #QmitkModels/QmitkDataStorageListModel.cpp #QmitkModels/QmitkPropertiesTableModel.cpp #QmitkModels/QmitkDataStorageTreeModel.cpp #QmitkModels/QmitkDataStorageTableModel.cpp #QmitkModels/QmitkPropertyDelegate.cpp #QmitkModels/QmitkPointListModel.cpp #QmitkAlgorithmFunctionalityComponent.cpp #QmitkBaseAlgorithmComponent.cpp QmitkAboutDialog/QmitkAboutDialog.cpp #QmitkFunctionalityComponents/QmitkSurfaceCreatorComponent.cpp #QmitkFunctionalityComponents/QmitkPixelGreyValueManipulatorComponent.cpp #QmitkFunctionalityComponents/QmitkConnectivityFilterComponent.cpp #QmitkFunctionalityComponents/QmitkImageCropperComponent.cpp #QmitkFunctionalityComponents/QmitkSeedPointSetComponent.cpp #QmitkFunctionalityComponents/QmitkSurfaceTransformerComponent.cpp QmitkPropertyObservers/QmitkBasePropertyView.cpp QmitkPropertyObservers/QmitkBoolPropertyWidget.cpp QmitkPropertyObservers/QmitkColorPropertyEditor.cpp QmitkPropertyObservers/QmitkColorPropertyView.cpp QmitkPropertyObservers/QmitkEnumerationPropertyWidget.cpp QmitkPropertyObservers/QmitkNumberPropertyEditor.cpp QmitkPropertyObservers/QmitkNumberPropertyView.cpp QmitkPropertyObservers/QmitkPropertyViewFactory.cpp QmitkPropertyObservers/QmitkStringPropertyEditor.cpp QmitkPropertyObservers/QmitkStringPropertyOnDemandEdit.cpp QmitkPropertyObservers/QmitkStringPropertyView.cpp QmitkPropertyObservers/QmitkNumberPropertySlider.cpp QmitkPropertyObservers/QmitkUGCombinedRepresentationPropertyWidget.cpp qclickablelabel.cpp #QmitkAbortEventFilter.cpp # QmitkApplicationCursor.cpp QmitkCallbackFromGUIThread.cpp QmitkEditPointDialog.cpp QmitkExtRegisterClasses.cpp QmitkFileChooser.cpp # QmitkRenderingManager.cpp # QmitkRenderingManagerFactory.cpp # QmitkRenderWindow.cpp # QmitkEventAdapter.cpp QmitkFloatingPointSpanSlider.cpp QmitkColorTransferFunctionCanvas.cpp QmitkSlicesInterpolator.cpp QmitkStandardViews.cpp QmitkStepperAdapter.cpp # QmitkLineEditLevelWindowWidget.cpp # mitkSliderLevelWindowWidget.cpp # QmitkLevelWindowWidget.cpp # QmitkPointListWidget.cpp # QmitkPointListView.cpp QmitkPiecewiseFunctionCanvas.cpp QmitkSliderNavigatorWidget.cpp QmitkTransferFunctionCanvas.cpp QmitkCrossWidget.cpp #QmitkLevelWindowRangeChangeDialog.cpp #QmitkLevelWindowPresetDefinitionDialog.cpp # QmitkLevelWindowWidgetContextMenu.cpp QmitkSliceWidget.cpp # QmitkStdMultiWidget.cpp QmitkTransferFunctionWidget.cpp QmitkTransferFunctionGeneratorWidget.cpp QmitkSelectableGLWidget.cpp QmitkToolReferenceDataSelectionBox.cpp QmitkToolWorkingDataSelectionBox.cpp QmitkToolGUIArea.cpp QmitkToolSelectionBox.cpp # QmitkPropertyListPopup.cpp QmitkToolGUI.cpp QmitkNewSegmentationDialog.cpp QmitkPaintbrushToolGUI.cpp QmitkDrawPaintbrushToolGUI.cpp QmitkErasePaintbrushToolGUI.cpp QmitkBinaryThresholdToolGUI.cpp QmitkCalculateGrayValueStatisticsToolGUI.cpp QmitkCopyToClipBoardDialog.cpp # QmitkMaterialEditor.cpp # QmitkMaterialShowcase.cpp # QmitkPropertiesTableEditor.cpp QmitkPrimitiveMovieNavigatorWidget.cpp # QmitkDataStorageComboBox.cpp QmitkHistogram.cpp QmitkHistogramWidget.cpp QmitkPlotWidget.cpp QmitkPlotDialog.cpp QmitkPointListModel.cpp QmitkPointListView.cpp QmitkPointListWidget.cpp QmitkPointListViewWidget.cpp QmitkCorrespondingPointSetsView.cpp QmitkCorrespondingPointSetsModel.cpp QmitkCorrespondingPointSetsWidget.cpp QmitkVideoBackground.cpp QmitkHotkeyLineEdit.cpp QmitkErodeToolGUI.cpp QmitkDilateToolGUI.cpp QmitkMorphologicToolGUI.cpp QmitkOpeningToolGUI.cpp QmitkClosingToolGUI.cpp QmitkBinaryThresholdULToolGUI.cpp QmitkPixelManipulationToolGUI.cpp QmitkRegionGrow3DToolGUI.cpp QmitkToolRoiDataSelectionBox.cpp QmitkBoundingObjectWidget.cpp ) IF ( NOT ${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}.${VTK_BUILD_VERSION} VERSION_LESS 5.4.0 ) SET(CPP_FILES ${CPP_FILES} QmitkVtkHistogramWidget.cpp QmitkVtkLineProfileWidget.cpp ) ENDIF() IF (NOT APPLE) SET(CPP_FILES ${CPP_FILES} QmitkBaseComponent.cpp QmitkBaseFunctionalityComponent.cpp QmitkFunctionalityComponentContainer.cpp QmitkFunctionalityComponents/QmitkThresholdComponent.cpp ) ENDIF() QT4_ADD_RESOURCES(CPP_FILES resources/QmitkResources.qrc) SET(MOC_H_FILES QmitkPropertyObservers/QmitkBasePropertyView.h QmitkPropertyObservers/QmitkBoolPropertyWidget.h QmitkPropertyObservers/QmitkColorPropertyEditor.h QmitkPropertyObservers/QmitkColorPropertyView.h QmitkPropertyObservers/QmitkEnumerationPropertyWidget.h QmitkPropertyObservers/QmitkNumberPropertyEditor.h QmitkPropertyObservers/QmitkNumberPropertyView.h QmitkPropertyObservers/QmitkStringPropertyEditor.h QmitkPropertyObservers/QmitkStringPropertyOnDemandEdit.h QmitkPropertyObservers/QmitkStringPropertyView.h QmitkPropertyObservers/QmitkNumberPropertySlider.h QmitkPropertyObservers/QmitkUGCombinedRepresentationPropertyWidget.h # QmitkFunctionalityComponents/QmitkSurfaceCreatorComponent.h #QmitkFunctionalityComponents/QmitkPixelGreyValueManipulatorComponent.h # QmitkFunctionalityComponents/QmitkConnectivityFilterComponent.h # QmitkFunctionalityComponents/QmitkImageCropperComponent.h # QmitkFunctionalityComponents/QmitkSeedPointSetComponent.h # QmitkFunctionalityComponents/QmitkSurfaceTransformerComponent.h qclickablelabel.h QmitkCallbackFromGUIThread.h QmitkEditPointDialog.h #QmitkAlgorithmFunctionalityComponent.h #QmitkBaseAlgorithmComponent.h QmitkStandardViews.h QmitkStepperAdapter.h QmitkSliderNavigatorWidget.h QmitkSliceWidget.h QmitkSlicesInterpolator.h QmitkColorTransferFunctionCanvas.h QmitkPiecewiseFunctionCanvas.h QmitkTransferFunctionCanvas.h QmitkFloatingPointSpanSlider.h QmitkCrossWidget.h QmitkTransferFunctionWidget.h QmitkTransferFunctionGeneratorWidget.h QmitkToolGUIArea.h QmitkToolGUI.h QmitkToolReferenceDataSelectionBox.h QmitkToolWorkingDataSelectionBox.h QmitkToolSelectionBox.h # QmitkPropertyListPopup.h #QmitkSelectableGLWidget.h QmitkNewSegmentationDialog.h QmitkPaintbrushToolGUI.h QmitkDrawPaintbrushToolGUI.h QmitkErasePaintbrushToolGUI.h QmitkBinaryThresholdToolGUI.h QmitkCalculateGrayValueStatisticsToolGUI.h QmitkCopyToClipBoardDialog.h QmitkPrimitiveMovieNavigatorWidget.h + QmitkPlotWidget.h QmitkPointListModel.h QmitkPointListView.h QmitkPointListWidget.h QmitkPointListViewWidget.h QmitkCorrespondingPointSetsView.h QmitkCorrespondingPointSetsModel.h QmitkCorrespondingPointSetsWidget.h QmitkHistogramWidget.h QmitkVideoBackground.h QmitkFileChooser.h QmitkHotkeyLineEdit.h QmitkAboutDialog/QmitkAboutDialog.h QmitkErodeToolGUI.h QmitkDilateToolGUI.h QmitkMorphologicToolGUI.h QmitkOpeningToolGUI.h QmitkClosingToolGUI.h QmitkBinaryThresholdULToolGUI.h QmitkPixelManipulationToolGUI.h QmitkRegionGrow3DToolGUI.h QmitkToolRoiDataSelectionBox.h QmitkBoundingObjectWidget.h ) IF ( NOT ${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}.${VTK_BUILD_VERSION} VERSION_LESS 5.4.0 ) SET(MOC_H_FILES ${MOC_H_FILES} QmitkVtkHistogramWidget.h QmitkVtkLineProfileWidget.h ) ENDIF() IF (NOT APPLE) SET(MOC_H_FILES ${MOC_H_FILES} QmitkBaseComponent.h QmitkBaseFunctionalityComponent.h QmitkFunctionalityComponentContainer.h QmitkFunctionalityComponents/QmitkThresholdComponent.h ) ENDIF() SET(UI_FILES QmitkSliderNavigator.ui # QmitkLevelWindowRangeChange.ui # QmitkLevelWindowPresetDefinition.ui # QmitkLevelWindowWidget.ui QmitkSliceWidget.ui QmitkTransferFunctionWidget.ui QmitkTransferFunctionGeneratorWidget.ui QmitkSelectableGLWidget.ui QmitkPrimitiveMovieNavigatorWidget.ui QmitkFunctionalityComponentContainerControls.ui QmitkFunctionalityComponents/QmitkThresholdComponentControls.ui QmitkAboutDialog/QmitkAboutDialogGUI.ui ) SET(QRC_FILES QmitkExt.qrc )