diff --git a/Modules/Core/include/mitkImagePixelAccessor.h b/Modules/Core/include/mitkImagePixelAccessor.h index e5b99c9432..479908099a 100644 --- a/Modules/Core/include/mitkImagePixelAccessor.h +++ b/Modules/Core/include/mitkImagePixelAccessor.h @@ -1,138 +1,142 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKIMAGEPIXELACCESSOR_H #define MITKIMAGEPIXELACCESSOR_H #include "mitkImage.h" #include "mitkImageDataItem.h" #include namespace mitk { /** * @brief Provides templated image access for all inheriting classes * @tparam TPixel defines the PixelType * @tparam VDimension defines the dimension for accessing data * @ingroup Data */ template class ImagePixelAccessor { public: typedef itk::Index IndexType; typedef ImagePixelAccessor ImagePixelAccessorType; typedef Image::ConstPointer ImageConstPointer; /** Get Dimensions from ImageDataItem */ int GetDimension(int i) const { return m_ImageDataItem->GetDimension(i); } private: friend class Image; protected: /** \param ImageDataItem* specifies the allocated image part */ ImagePixelAccessor(ImageConstPointer iP, const mitk::ImageDataItem *iDI) : m_ImageDataItem(iDI) { if (iDI == nullptr) { m_ImageDataItem = iP->GetChannelData(); } CheckData(iP.GetPointer()); } /** Destructor */ virtual ~ImagePixelAccessor() {} void CheckData( const Image *image ) { // Check if Dimensions are correct if ( m_ImageDataItem == nullptr ) { if ( image->GetDimension() != VDimension ) { mitkThrow() << "Invalid ImageAccessor: The Dimensions of ImageAccessor and Image are not equal." << " They have to be equal if an entire image is requested." << " image->GetDimension(): " << image->GetDimension() << " , VDimension: " << VDimension; } } else { if ( m_ImageDataItem->GetDimension() != VDimension ) { mitkThrow() << "Invalid ImageAccessor: The Dimensions of ImageAccessor and ImageDataItem are not equal." << " m_ImageDataItem->GetDimension(): " << m_ImageDataItem->GetDimension() << " , VDimension: " << VDimension; } } if (!( image->GetPixelType() == mitk::MakePixelType< itk::Image< TPixel, VDimension > >() || image->GetPixelType() == mitk::MakePixelType< itk::VectorImage< TPixel, VDimension > > ( image->GetPixelType().GetNumberOfComponents() ) ) ) { mitkThrow() << "Invalid ImageAccessor: PixelTypes of Image and ImageAccessor are not equal." << " image->GetPixelType(): " << typeid(image->GetPixelType()).name() << "\n m_ImageDataItem->GetDimension(): " << m_ImageDataItem->GetDimension() << " , VDimension: " << VDimension << " , TPixel: " << typeid(TPixel).name() << " , NumberOfComponents: " << image->GetPixelType().GetNumberOfComponents() << std::endl; } } /** Holds the specified ImageDataItem */ const ImageDataItem *m_ImageDataItem; /** \brief Pointer to the used Geometry. * Since Geometry can be different to the Image (if memory was forced to be coherent) it is necessary to store * Geometry separately. */ BaseGeometry::Pointer m_Geometry; /** \brief A Subregion defines an arbitrary area within the image. * If no SubRegion is defined, the whole ImageDataItem or Image is regarded. * A subregion (e.g. subvolume) can lead to non-coherent memory access where every dimension has a start- and * end-offset. */ itk::ImageRegion *m_SubRegion; /** \brief Stores all extended properties of an ImageAccessor. * The different flags in mitk::ImageAccessorBase::Options can be unified by bitwise operations. */ int m_Options; /** Get memory offset for a given image index */ unsigned int GetOffset(const IndexType &idx) const { const unsigned int *imageDims = m_ImageDataItem->m_Dimensions; unsigned int offset = 0; switch (VDimension) { case 4: offset += idx[3] * imageDims[0] * imageDims[1] * imageDims[2]; + /* FALLTHRU */ case 3: offset += idx[2] * imageDims[0] * imageDims[1]; + /* FALLTHRU */ case 2: offset += idx[0] + idx[1] * imageDims[0]; + /* FALLTHRU */ + default: break; } return offset; } }; } #endif // MITKIMAGEACCESSOR_H diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkOdfMaximaExtractionFilter.cpp b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkOdfMaximaExtractionFilter.cpp index fd04aab03e..cbb87a77f4 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkOdfMaximaExtractionFilter.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkOdfMaximaExtractionFilter.cpp @@ -1,629 +1,637 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkOdfMaximaExtractionFilter_cpp #define __itkOdfMaximaExtractionFilter_cpp #include "itkOdfMaximaExtractionFilter.h" #include #include #include #include #include #include #include #include #include #include #include using namespace boost::math; using namespace std; namespace itk { template< class TOdfPixelType > OdfMaximaExtractionFilter< TOdfPixelType >::OdfMaximaExtractionFilter(): m_NormalizationMethod(MAX_VEC_NORM), m_PeakThreshold(0.2), m_MaxNumPeaks(10), m_ShCoeffImage(nullptr), m_OutputFiberBundle(nullptr), m_NumDirectionsImage(nullptr), m_DirectionImageContainer(nullptr) { } // solve ax? + bx? + cx + d = 0 using cardanos method template< class TOdfPixelType > bool OdfMaximaExtractionFilter::ReconstructQballImage() { if (m_ShCoeffImage.IsNotNull()) { cout << "Using preset coefficient image\n"; return true; } cout << "Starting qball reconstruction\n"; try { QballReconstructionFilterType::Pointer filter = QballReconstructionFilterType::New(); filter->SetBValue(m_Bvalue); filter->SetGradientImage( m_DiffusionGradients, m_DiffusionImage ); filter->SetLambda(0.006); filter->SetNormalizationMethod(QballReconstructionFilterType::QBAR_SOLID_ANGLE); filter->Update(); m_ShCoeffImage = filter->GetCoefficientImage(); if (m_ShCoeffImage.IsNull()) return false; return true; } catch (...) { return false; } } // solve ax³ + bx² + cx + d = 0 using cardanos method template< class TOdfPixelType > std::vector OdfMaximaExtractionFilter< TOdfPixelType > ::SolveCubic(const double& a, const double& b, const double& c, const double& d) { double A, B, p, q, r, D, offset, ee, tmp, root; vector roots; double inv3 = 1.0/3.0; if (a!=0) // solve ax³ + bx² + cx + d = 0 { p = b/a; q = c/a; r = d/a; // x³ + px² + qx + r = 0 A = q-p*p*inv3; B = (2.0*p*p*p-9.0*p*q+27.0*r)/27.0; A = A*inv3; B = B*0.5; D = B*B+A*A*A; offset = p*inv3; if (D>0.0) // one real root { ee = sqrt(D); tmp = -B+ee; root = cbrt(tmp); tmp = -B-ee; root += cbrt(tmp); root -= offset; roots.push_back(root); } else if (D<0.0) // three real roots { ee = sqrt(-D); double tmp2 = -B; double angle = 2.0*inv3*atan(ee/(sqrt(tmp2*tmp2+ee*ee)+tmp2)); double sqrt3 = sqrt(3.0); tmp = cos(angle); tmp2 = sin(angle); ee = sqrt(-A); root = 2*ee*tmp-offset; roots.push_back(root); root = -ee*(tmp+sqrt3*tmp2)-offset; roots.push_back(root); root = -ee*(tmp-sqrt3*tmp2)-offset; roots.push_back(root); } else // one or two real roots { tmp=-B; tmp=cbrt(tmp); root=2*tmp-offset; roots.push_back(root); + // TODO: check if this is correct (see history) if (A!=0 || B!=0) + { root=-tmp-offset; roots.push_back(root); + } } } else if (b!=0) // solve bx² + cx + d = 0 { D = c*c-4*b*d; if (D>0) { tmp = sqrt(D); root = (-c+tmp)/(2.0*b); roots.push_back(root); root = (-c-tmp)/(2.0*b); roots.push_back(root); } + // TODO: check if this is correct (see history) else if (D==0) + { root = -c/(2.0*b); roots.push_back(root); + } } + // TODO: check if this is correct (see history) else if (c!=0) // solve cx + d = 0 + { root = -d/c; roots.push_back(root); - + } return roots; } template< class TOdfPixelType > double OdfMaximaExtractionFilter< TOdfPixelType > ::ODF_dtheta(const double& sn, const double& cs, const double& A, const double& B, const double& C, const double& D, const double& E, const double& F, const double& G, const double& H) { double dtheta=(G-7*E)*sn*sn + (7*F-35*D-H)*sn*cs + (H+C-F-3*A-5*D)*sn + (0.5*E+B+0.5*G)*cs -0.5*G+3.5*E; return dtheta; } template< class TOdfPixelType > double OdfMaximaExtractionFilter< TOdfPixelType > ::ODF_dtheta2(const double& sn, const double& cs, const double& A, const double& B, const double& C, const double& D, const double& E, const double& F, const double& G, const double& H) { double dtheta2=4*(G-7*E)*sn*cs + 2*(7*F-35*D-H)*(2*cs*cs-1) + 2*(H+C-F-3*A-5*D)*cs -(E+2*B+G)*sn; return dtheta2; } template< class TOdfPixelType > double OdfMaximaExtractionFilter< TOdfPixelType > ::ODF_dphi2(const double& sn, const double& cs, const double& A, const double& B, const double& C, const double& D, const double& E, const double& F, const double& G, const double& H) { double dphi2=35*D*((1+cs)*(1+cs)/4)+(3*A-30*D)*(1+cs)/2.0+3*D-A + 0.5*(7*E*(1+cs)/2.0-3*E+B)*sn + (7*F*(1+cs)/2+C-F)*(1-cs)/2.0 + G*sn*(1-cs)/4.0 + H*((1-cs)*(1-cs)/4); return dphi2; } template< class TOdfPixelType > void OdfMaximaExtractionFilter< TOdfPixelType > ::FindCandidatePeaks(const CoefficientPixelType& SHcoeff) { const double thr = 0.03; // threshold on the derivative of the ODF with respect to theta const double phi_step = 0.005; // step size for 1D exhaustive search on phi bool highRes; // when close to maxima increase resolution double mag, Y, Yp, sn, cs; double phi, dPhi; double A, B, C, D, E, F, G, H, Bp, Cp, Ep, Fp, Gp, Hp, Bs, Cs, Es, Fs, Gs, Hs; CoefficientPixelType a, ap; a = SHcoeff; ap = SHcoeff; m_CandidatePeaks.clear(); // clear peaks of last voxel for (int adaptiveStepwidth=0; adaptiveStepwidth<=1; adaptiveStepwidth++) { phi=0; while (phi<(2*M_PI)) // phi exhaustive search 0..pi { // calculate 4th order SH representtaion of ODF and according derivative for (int l=0; l<=4; l=l+2) { for (int m=-l; m<=l; m++) { int j=l*(l+1)/2+m; if (m<0) { mag = sqrt(((2*l+1)/(2*M_PI))*factorial(l+m)/factorial(l-m)); Y = mag*cos(m*phi); Yp = -m*mag*sin(m*phi); } else if (m==0) { Y = sqrt((2*l+1)/(4*M_PI)); Yp = 0; } else { mag = pow(-1.0,m)*sqrt(((2*l+1)/(2*M_PI))*factorial(l-m)/factorial(l+m)); Y = mag*sin(m*phi); Yp = m*mag*cos(m*phi); } a[j] = SHcoeff[j]*Y; ap[j] = SHcoeff[j]*Yp; } } // ODF A=0.5*a[3]; B=-3*(a[2]+a[4]); C=3*(a[1]+a[5]); D=0.125*a[10]; E=-2.5*(a[9]+a[11]); F=7.5*(a[8]+a[12]); G=-105*(a[7]+a[13]); H=105*(a[6]+a[14]); // phi derivative Bp=-3*(ap[2]+ap[4]); Cp=3*(ap[1]+ap[5]); Ep=-2.5*(ap[9]+ap[11]); Fp=7.5*(ap[8]+ap[12]); Gp=-105*(ap[7]+ap[13]); Hp=105*(ap[6]+ap[14]); // 2phi derivative Bs=-B; Cs=-4*C; Es=-E; Fs=-4*F; Gs=-9*G; Hs=-16*H; // solve cubic for tan(theta) std::vector tanTheta = SolveCubic(Hp+Cp-Fp, Gp+Bp-3*Ep, 6*Fp+Cp, Bp+4*Ep); highRes = false; dPhi = phi_step; //for each real cubic solution for tan(theta) for (int n=0; n hessian; hessian(0,0) = ODF_dtheta2(sn, cs, A, B, C, D, E, F, G, H); hessian(0,1) = ODF_dtheta(sn, cs, 0, Bp, Cp, 0, Ep, Fp, Gp, Hp); hessian(1,0) = hessian(0,1); hessian(1,1) = ODF_dphi2(sn, cs, 0, Bs, Cs, 0, Es, Fs, Gs, Hs); double det = vnl_det(hessian); // determinant double tr = vnl_trace(hessian); // trace highRes = true; // we are close to a maximum, so turn on high resolution 1D exhaustive search if (det>=0 && tr<=0) // check if we really have a local maximum { vnl_vector_fixed< double, 2 > peak; peak[0] = theta; peak[1] = phi; m_CandidatePeaks.push_back(peak); } } if (adaptiveStepwidth) // calculate adaptive step width { double t2=tanTheta[n]*tanTheta[n]; double t3=t2*tanTheta[n]; double t4=t3*tanTheta[n]; double const_step=phi_step*(1+t2)/sqrt(t2+t4+pow((((Hs+Cs-Fs)*t3+(Gs+Bs-3*Es)*t2+(6*Fs+Cs)*tanTheta[n]+(Bs+4*Es))/(3*(Hp+Cp-Fp)*t2+2*(Gp+Bp-3*Ep)*tanTheta[n]+(6*Fp+Cp))),2.0)); if (const_step std::vector< vnl_vector_fixed< double, 3 > > OdfMaximaExtractionFilter< TOdfPixelType > ::ClusterPeaks(const CoefficientPixelType& shCoeff) { const double distThres = 0.4; int npeaks = 0, nMin = 0; double dMin, dPos, dNeg, d; Vector3D u; vector< Vector3D > v; // initialize container for vector clusters std::vector < std::vector< Vector3D > > clusters; clusters.resize(m_CandidatePeaks.size()); for (int i=0; i::max(); for (int n=0; n shBasis, sphCoords; Cart2Sph(v, sphCoords); // convert candidate peaks to spherical angles shBasis = CalcShBasis(sphCoords, 4); // evaluate spherical harmonics at each peak vnl_vector odfVals(npeaks); odfVals.fill(0.0); double maxVal = itk::NumericTraits::NonpositiveMin(); int maxPos; for (int i=0; imaxVal ) { maxVal = odfVals(i); maxPos = i; } } v.clear(); vector< double > restVals; for (int i=0; i=m_PeakThreshold*maxVal ) { u[0] = odfVals(i)*cos(sphCoords(i,1))*sin(sphCoords(i,0)); u[1] = odfVals(i)*sin(sphCoords(i,1))*sin(sphCoords(i,0)); u[2] = odfVals(i)*cos(sphCoords(i,0)); restVals.push_back(odfVals(i)); v.push_back(u); } npeaks = v.size(); if (npeaks>m_MaxNumPeaks) // if still too many peaks, keep only the m_MaxNumPeaks with maximum value { vector< Vector3D > v2; for (int i=0; i::NonpositiveMin(); //Get the maximum ODF peak value and the corresponding peak index for (int i=0; imaxVal ) { maxVal = restVals[i]; maxPos = i; } v2.push_back(v[maxPos]); restVals[maxPos] = 0; //zero that entry in order to find the next maximum } return v2; } } return v; } // convert cartesian to spherical coordinates template< class TOdfPixelType > void OdfMaximaExtractionFilter< TOdfPixelType > ::Cart2Sph(const std::vector< Vector3D >& dir, vnl_matrix& sphCoords) { sphCoords.set_size(dir.size(), 2); for (int i=0; i vnl_matrix OdfMaximaExtractionFilter< TOdfPixelType > ::CalcShBasis(vnl_matrix& sphCoords, const int& shOrder) { int R = (shOrder+1)*(shOrder+2)/2; int M = sphCoords.rows(); int j, m; double mag, plm; vnl_matrix shBasis; shBasis.set_size(M,R); for (int p=0; p(l,abs(m),cos(sphCoords(p,0))); mag = sqrt((double)(2*l+1)/(4.0*M_PI)*factorial(l-abs(m))/factorial(l+abs(m)))*plm; if (m<0) shBasis(p,j) = sqrt(2.0)*mag*cos(fabs((double)m)*sphCoords(p,1)); else if (m==0) shBasis(p,j) = mag; else shBasis(p,j) = pow(-1.0, m)*sqrt(2.0)*mag*sin(m*sphCoords(p,1)); j++; } } return shBasis; } template< class TOdfPixelType > void OdfMaximaExtractionFilter< TOdfPixelType > ::GenerateData() { if (!ReconstructQballImage()) return; std::cout << "Starting maxima extraction\n"; switch (m_NormalizationMethod) { case NO_NORM: std::cout << "NO_NORM\n"; break; case SINGLE_VEC_NORM: std::cout << "SINGLE_VEC_NORM\n"; break; case MAX_VEC_NORM: std::cout << "MAX_VEC_NORM\n"; break; } typedef ImageRegionConstIterator< CoefficientImageType > InputIteratorType; InputIteratorType git(m_ShCoeffImage, m_ShCoeffImage->GetLargestPossibleRegion() ); itk::Vector spacing = m_ShCoeffImage->GetSpacing(); double minSpacing = spacing[0]; if (spacing[1]GetOrigin(); itk::Matrix direction = m_ShCoeffImage->GetDirection(); ImageRegion<3> imageRegion = m_ShCoeffImage->GetLargestPossibleRegion(); // initialize num directions image m_NumDirectionsImage = ItkUcharImgType::New(); m_NumDirectionsImage->SetSpacing( spacing ); m_NumDirectionsImage->SetOrigin( origin ); m_NumDirectionsImage->SetDirection( direction ); m_NumDirectionsImage->SetRegions( imageRegion ); m_NumDirectionsImage->Allocate(); m_NumDirectionsImage->FillBuffer(0); vtkSmartPointer m_VtkCellArray = vtkSmartPointer::New(); vtkSmartPointer m_VtkPoints = vtkSmartPointer::New(); m_DirectionImageContainer = ItkDirectionImageContainer::New(); for (int i=0; i nullVec; nullVec.Fill(0.0); ItkDirectionImage::Pointer img = ItkDirectionImage::New(); img->SetSpacing( spacing ); img->SetOrigin( origin ); img->SetDirection( direction ); img->SetRegions( imageRegion ); img->Allocate(); img->FillBuffer(nullVec); m_DirectionImageContainer->InsertElement(m_DirectionImageContainer->Size(), img); } if (m_MaskImage.IsNull()) { m_MaskImage = ItkUcharImgType::New(); m_MaskImage->SetSpacing( spacing ); m_MaskImage->SetOrigin( origin ); m_MaskImage->SetDirection( direction ); m_MaskImage->SetRegions( imageRegion ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1); } itk::ImageRegionIterator dirIt(m_NumDirectionsImage, m_NumDirectionsImage->GetLargestPossibleRegion()); itk::ImageRegionIterator maskIt(m_MaskImage, m_MaskImage->GetLargestPossibleRegion()); int maxProgress = m_MaskImage->GetLargestPossibleRegion().GetSize()[0]*m_MaskImage->GetLargestPossibleRegion().GetSize()[1]*m_MaskImage->GetLargestPossibleRegion().GetSize()[2]; boost::progress_display disp(maxProgress); git.GoToBegin(); while( !git.IsAtEnd() ) { ++disp; if (maskIt.Value()<=0) { ++git; ++dirIt; ++maskIt; continue; } CoefficientPixelType c = git.Get(); FindCandidatePeaks(c); std::vector< Vector3D > directions = ClusterPeaks(c); typename CoefficientImageType::IndexType index = git.GetIndex(); float max = 0.0; for (int i=0; imax) max = directions.at(i).magnitude(); if (max<0.0001) max = 1.0; for (int i=0; iGetElement(i); itk::Vector< float, 3 > pixel; vnl_vector dir = directions.at(i); vtkSmartPointer container = vtkSmartPointer::New(); itk::ContinuousIndex center; center[0] = index[0]; center[1] = index[1]; center[2] = index[2]; itk::Point worldCenter; m_ShCoeffImage->TransformContinuousIndexToPhysicalPoint( center, worldCenter ); switch (m_NormalizationMethod) { case NO_NORM: break; case SINGLE_VEC_NORM: dir.normalize(); break; case MAX_VEC_NORM: dir /= max; break; } dir = m_MaskImage->GetDirection()*dir; pixel.SetElement(0, dir[0]); pixel.SetElement(1, dir[1]); pixel.SetElement(2, dir[2]); img->SetPixel(index, pixel); itk::Point worldStart; worldStart[0] = worldCenter[0]-dir[0]/2 * minSpacing; worldStart[1] = worldCenter[1]-dir[1]/2 * minSpacing; worldStart[2] = worldCenter[2]-dir[2]/2 * minSpacing; vtkIdType id = m_VtkPoints->InsertNextPoint(worldStart.GetDataPointer()); container->GetPointIds()->InsertNextId(id); itk::Point worldEnd; worldEnd[0] = worldCenter[0]+dir[0]/2 * minSpacing; worldEnd[1] = worldCenter[1]+dir[1]/2 * minSpacing; worldEnd[2] = worldCenter[2]+dir[2]/2 * minSpacing; id = m_VtkPoints->InsertNextPoint(worldEnd.GetDataPointer()); container->GetPointIds()->InsertNextId(id); m_VtkCellArray->InsertNextCell(container); } dirIt.Set(directions.size()); ++git; ++dirIt; ++maskIt; } vtkSmartPointer directionsPolyData = vtkSmartPointer::New(); directionsPolyData->SetPoints(m_VtkPoints); directionsPolyData->SetLines(m_VtkCellArray); m_OutputFiberBundle = mitk::FiberBundle::New(directionsPolyData); std::cout << "Maxima extraction finished\n"; } } #endif // __itkOdfMaximaExtractionFilter_cpp diff --git a/Modules/IGT/Common/mitkSerialCommunication.cpp b/Modules/IGT/Common/mitkSerialCommunication.cpp index c7138a9dc6..79b51a8d66 100644 --- a/Modules/IGT/Common/mitkSerialCommunication.cpp +++ b/Modules/IGT/Common/mitkSerialCommunication.cpp @@ -1,511 +1,514 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkSerialCommunication.h" #ifdef WIN32 //#include #include #else // Posix #include #include #include #include #include #include #include #include #define INVALID_HANDLE_VALUE -1 #endif #define OK 1 #define ERROR_VALUE 0 mitk::SerialCommunication::SerialCommunication() : itk::Object(), m_DeviceName(""), m_PortNumber(COM1), m_BaudRate(BaudRate9600), m_DataBits(DataBits8), m_Parity(None), m_StopBits(StopBits1), m_HardwareHandshake(HardwareHandshakeOff), m_ReceiveTimeout(500), m_SendTimeout(500), m_Connected(false) { #ifdef WIN32 // Windows m_ComPortHandle = INVALID_HANDLE_VALUE; #else // Posix m_FileDescriptor = INVALID_HANDLE_VALUE; #endif } mitk::SerialCommunication::~SerialCommunication() { CloseConnection(); } bool mitk::SerialCommunication::IsConnected() { return m_Connected; } int mitk::SerialCommunication::OpenConnection() { if (m_Connected) return ERROR_VALUE; #ifdef WIN32 std::stringstream ss; if (m_DeviceName.empty()) ss << "\\\\.\\COM" << static_cast(m_PortNumber); // use m_PortNumber else ss << "\\\\.\\" << m_DeviceName; // use m_DeviceName m_ComPortHandle = CreateFile(ss.str().c_str(), GENERIC_READ | GENERIC_WRITE, 0, // no sharing 0, // no security flags OPEN_EXISTING, // open com port, don't create it 0, // no flags 0); // no template if (m_ComPortHandle == INVALID_HANDLE_VALUE) return ERROR_VALUE; GetCommState(m_ComPortHandle, &m_PreviousDeviceControlBlock); GetCommTimeouts(m_ComPortHandle, &m_PreviousTimeout); GetCommMask(m_ComPortHandle, &m_PreviousMask); if (this->ApplyConfiguration() != OK) // set interface parameters { CloseHandle(m_ComPortHandle); m_ComPortHandle = INVALID_HANDLE_VALUE; return ERROR_VALUE; } m_Connected = true; return OK; #else // Posix std::stringstream ss; if (m_DeviceName.empty()) ss << "/dev/ttyS" << static_cast(m_PortNumber) - 1; // use m_PortNumber, COM1 = ttyS0 else ss << m_DeviceName; // use m_DeviceName //m_FileDescriptor = open(ss.str().c_str(), O_RDWR | O_NONBLOCK | O_NDELAY | O_NOCTTY | O_EXCL); // open device file m_FileDescriptor = open(ss.str().c_str(), O_RDWR|O_NONBLOCK|O_EXCL); // open device file if (m_FileDescriptor < 0) return ERROR_VALUE; fcntl(m_FileDescriptor, F_SETFL, 0); // change to blocking mode tcflush(m_FileDescriptor, TCIOFLUSH); // flush buffers if (this->ApplyConfiguration() != OK) // set interface parameters { close(m_FileDescriptor); m_FileDescriptor = INVALID_HANDLE_VALUE; return ERROR_VALUE; } m_Connected = true; return OK; #endif } void mitk::SerialCommunication::CloseConnection() { #ifdef WIN32 if (m_ComPortHandle == INVALID_HANDLE_VALUE) return; ClearReceiveBuffer(); ClearSendBuffer(); SetCommState(m_ComPortHandle, &m_PreviousDeviceControlBlock); // restore previous settings SetCommTimeouts(m_ComPortHandle, &m_PreviousTimeout); // restore previous timeout values SetCommMask(m_ComPortHandle, m_PreviousMask); // restore previous mask value PurgeComm(m_ComPortHandle, PURGE_TXCLEAR | PURGE_RXCLEAR); // empty buffers CloseHandle(m_ComPortHandle); // close handle m_ComPortHandle = INVALID_HANDLE_VALUE; m_Connected = false; return; #else // Posix if (m_FileDescriptor == INVALID_HANDLE_VALUE) return; ClearReceiveBuffer(); ClearSendBuffer(); close(m_FileDescriptor); m_FileDescriptor = INVALID_HANDLE_VALUE; m_Connected = false; return; #endif } int mitk::SerialCommunication::Receive(std::string& answer, unsigned int numberOfBytes, const char *eol) { if (numberOfBytes == 0) return OK; if (m_Connected == false) return ERROR_VALUE; #ifdef WIN32 if (m_ComPortHandle == INVALID_HANDLE_VALUE) return ERROR_VALUE; DWORD numberOfBytesRead = 0; char* buffer = new char[numberOfBytes]; if (ReadFile(m_ComPortHandle, buffer, numberOfBytes, &numberOfBytesRead, nullptr) != 0) { if (numberOfBytesRead > 0) // data read { answer.assign(buffer, numberOfBytesRead); // copy buffer to answer delete buffer; if (numberOfBytesRead == numberOfBytes) { return OK; // everything was received } else { return ERROR_VALUE; // some data was received, but not as much as expected } } else // error { answer = ""; delete buffer; return ERROR_VALUE; } } delete buffer; return OK; #else // Posix if (m_FileDescriptor == INVALID_HANDLE_VALUE) return ERROR_VALUE; unsigned long bytesRead = 0; unsigned long bytesLeft = numberOfBytes; auto buffer = new char[numberOfBytes]; while ((bytesLeft > 0) && (bytesRead < numberOfBytes)) { int num = read(m_FileDescriptor, &buffer[bytesRead], 1); // read one byte if (num == -1) // ERROR_VALUE { if (errno == EAGAIN) // nonblocking, no byte there right now, but maybe next time continue; else break; // ERROR_VALUE, stop trying to read } if (num == 0) // timeout or eof(?) break; bytesLeft -= num; // n is number of chars left to read bytesRead += num; // i is the number of chars read if (eol && *eol == buffer[bytesRead-1]) // end of line char reached break; } if (bytesRead > 0) answer.assign(buffer, bytesRead); // copy buffer to answer delete[] buffer; if ( bytesRead == numberOfBytes || // everything was received (eol && answer.size() > 0 && *eol == answer.at(answer.size()-1)) ) // end of line char reached return OK; else return ERROR_VALUE; // some data was received, but not as much as expected #endif } int mitk::SerialCommunication::Send(const std::string& input, bool block) { //long retval = E2ERR_OPENFAILED; if (input.empty()) return OK; if (m_Connected == false) return ERROR_VALUE; #ifdef WIN32 if (m_ComPortHandle == INVALID_HANDLE_VALUE) return ERROR_VALUE; DWORD bytesWritten = 0; if (WriteFile(m_ComPortHandle, input.data(), static_cast(input.size()), &bytesWritten, nullptr) == TRUE) return OK; else return GetLastError(); #else // Posix if (m_FileDescriptor == INVALID_HANDLE_VALUE) return ERROR_VALUE; long bytesWritten = 0; long bytesLeft = input.size(); while (bytesLeft > 0) { bytesWritten = write(m_FileDescriptor, input.data() + bytesWritten, bytesLeft); if (bytesWritten <= 0) return ERROR_VALUE; //return ERROR_VALUE bytesLeft -= bytesWritten; } if (block) { // wait for output to be physically sent if (tcdrain(m_FileDescriptor) == -1) return ERROR_VALUE; } return OK; #endif } int mitk::SerialCommunication::ApplyConfiguration() { #ifdef WIN32 // Windows implementation return ApplyConfigurationWin(); #else // Posix return ApplyConfigurationUnix(); #endif } /** * The Code for Baud rates is highly platform specific and divided into separate subroutines for readability. */ #ifdef WIN32 int mitk::SerialCommunication::ApplyConfigurationWin() { if (m_ComPortHandle == INVALID_HANDLE_VALUE) return ERROR_VALUE; DCB controlSettings; if (GetCommState(m_ComPortHandle, &controlSettings) == 0) { return ERROR_VALUE; } std::ostringstream o; o << "baud=" << m_BaudRate << " parity=" << static_cast(m_Parity) << " data=" << m_DataBits << " stop=" << m_StopBits; if (BuildCommDCBA(o.str().c_str(), &controlSettings) == 0) // Build device-control block return ERROR_VALUE; if (m_HardwareHandshake == HardwareHandshakeOn) // Modify hardware handshake values { controlSettings.fDtrControl = DTR_CONTROL_ENABLE; controlSettings.fRtsControl = RTS_CONTROL_ENABLE; controlSettings.fOutxCtsFlow = TRUE; controlSettings.fRtsControl = RTS_CONTROL_HANDSHAKE; } else { controlSettings.fDtrControl = DTR_CONTROL_DISABLE; controlSettings.fRtsControl = RTS_CONTROL_DISABLE; controlSettings.fOutxCtsFlow = FALSE; controlSettings.fRtsControl = RTS_CONTROL_DISABLE; } if (SetCommState(m_ComPortHandle, &controlSettings) == FALSE) // Configure com port return GetLastError(); COMMTIMEOUTS timeouts; timeouts.ReadIntervalTimeout = m_ReceiveTimeout; timeouts.ReadTotalTimeoutMultiplier = 0; timeouts.ReadTotalTimeoutConstant = m_ReceiveTimeout; timeouts.WriteTotalTimeoutMultiplier = 0; timeouts.WriteTotalTimeoutConstant = m_SendTimeout; if (SetCommTimeouts(m_ComPortHandle, &timeouts) == FALSE) // set timeout values return GetLastError(); PurgeComm(m_ComPortHandle, PURGE_TXCLEAR | PURGE_RXCLEAR); // clear read and write buffers return OK; } #else /** * \brief Applies the configuration for Linux */ int mitk::SerialCommunication::ApplyConfigurationUnix() { if ( m_FileDescriptor == INVALID_HANDLE_VALUE ) return ERROR_VALUE; struct termios termIOStructure; if ( tcgetattr(m_FileDescriptor, &termIOStructure) != 0 ) // retrieve parameters from com port return ERROR_VALUE; cfmakeraw(&termIOStructure); // set flags to raw mode termIOStructure.c_cflag |= CLOCAL; if (m_HardwareHandshake == HardwareHandshakeOn) { // enable termIOStructure.c_cflag |= CRTSCTS; termIOStructure.c_iflag &= ~(IXON|IXOFF); } else { // disable termIOStructure.c_cflag &= ~CRTSCTS; termIOStructure.c_iflag &= ~(IXON|IXOFF); } termIOStructure.c_cflag &= ~CSIZE; // set number of data bits switch (m_DataBits) { case DataBits7: termIOStructure.c_cflag |= CS7; break; case DataBits8: default: termIOStructure.c_cflag |= CS8; } switch (m_StopBits) // set number of stop bits { case StopBits2: termIOStructure.c_cflag |= CSTOPB; break; case StopBits1: default: termIOStructure.c_cflag &= ~CSTOPB; } switch (m_Parity) // set parity { case Odd: termIOStructure.c_cflag |= (PARENB|PARODD); break; case Even: termIOStructure.c_cflag |= PARENB; termIOStructure.c_cflag &= ~PARODD; + // TODO: check if this is intended + // FALLTHRU case None: + // FALLTHRU default: termIOStructure.c_cflag &= ~PARENB; break; } speed_t baudrate; // set baudrate switch (m_BaudRate) { case BaudRate9600: baudrate = B9600; break; case BaudRate14400: baudrate = B9600; //14400 is not defined for posix, use 9600 instead break; case BaudRate19200: baudrate = B19200; break; case BaudRate38400: baudrate = B38400; break; case BaudRate57600: baudrate = B57600; break; case BaudRate115200: baudrate = B115200; break; case BaudRate230400: baudrate = B230400; break; // the following baud rates do not work for apple #ifndef __APPLE__ case BaudRate460800: baudrate = B460800; break; case BaudRate500000: baudrate = B500000; break; case BaudRate576000: baudrate = B576000; break; case BaudRate921600: baudrate = B921600; break; case BaudRate1000000: baudrate = B1000000; break; case BaudRate1152000: baudrate = B1152000; break; //case BaudRate1228739: //baudrate = B1228739; //break; case BaudRate1500000: baudrate = B1500000; break; case BaudRate2000000: baudrate = B2000000; break; case BaudRate2500000: baudrate = B2500000; break; case BaudRate3000000: baudrate = B3000000; break; case BaudRate3500000: baudrate = B3500000; break; case BaudRate4000000: baudrate = B4000000; break; #endif default: MITK_WARN("mitk::SerialCommunication") << "Baud rate not recognized, using default of 9600 Baud."; baudrate = B9600; break; } cfsetispeed(&termIOStructure, baudrate); cfsetospeed(&termIOStructure, baudrate); termIOStructure.c_cc[VMIN] = 0; termIOStructure.c_cc[VTIME] = m_ReceiveTimeout / 100; // timeout in 1/10 sec, not in ms. Rounded down. if (tcsetattr(m_FileDescriptor, TCSANOW, &termIOStructure) == 0) return OK; else return ERROR_VALUE; } #endif void mitk::SerialCommunication::SendBreak(unsigned int ms) { #ifdef WIN32 if (m_ComPortHandle == INVALID_HANDLE_VALUE) return; SetCommBreak(m_ComPortHandle); itksys::SystemTools::Delay(ms); ClearCommBreak(m_ComPortHandle); return; #else // Posix if (m_FileDescriptor == INVALID_HANDLE_VALUE) return; tcsendbreak(m_FileDescriptor, ms); return; #endif } void mitk::SerialCommunication::ClearReceiveBuffer() { #ifdef WIN32 if (m_ComPortHandle != INVALID_HANDLE_VALUE) PurgeComm(m_ComPortHandle, PURGE_RXCLEAR); #else // Posix if (m_FileDescriptor != INVALID_HANDLE_VALUE) tcflush(m_FileDescriptor, TCIFLUSH); #endif } void mitk::SerialCommunication::ClearSendBuffer() { #ifdef WIN32 if ( m_ComPortHandle != INVALID_HANDLE_VALUE ) PurgeComm(m_ComPortHandle, PURGE_TXCLEAR); #else // Posix if ( m_FileDescriptor != INVALID_HANDLE_VALUE ) tcflush(m_FileDescriptor, TCOFLUSH); #endif } diff --git a/Modules/MapperExt/src/mitkMeshMapper2D.cpp b/Modules/MapperExt/src/mitkMeshMapper2D.cpp index 2160a83302..44b7765800 100644 --- a/Modules/MapperExt/src/mitkMeshMapper2D.cpp +++ b/Modules/MapperExt/src/mitkMeshMapper2D.cpp @@ -1,483 +1,476 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkMeshMapper2D.h" #include "mitkBaseRenderer.h" #include "mitkColorProperty.h" #include "mitkGL.h" #include "mitkLine.h" #include "mitkMesh.h" #include "mitkPlaneGeometry.h" #include "mitkProperties.h" #include #include const float selectedColor[] = {1.0f, 0.0f, 0.6f}; // for selected! mitk::MeshMapper2D::MeshMapper2D() { } mitk::MeshMapper2D::~MeshMapper2D() { } const mitk::Mesh *mitk::MeshMapper2D::GetInput(void) { return static_cast(GetDataNode()->GetData()); } // Return whether a point is "smaller" than the second static bool point3DSmaller(const mitk::Point3D &elem1, const mitk::Point3D &elem2) { if (elem1[0] != elem2[0]) return elem1[0] < elem2[0]; if (elem1[1] != elem2[1]) return elem1[1] < elem2[1]; return elem1[2] < elem2[2]; } void mitk::MeshMapper2D::Paint(mitk::BaseRenderer *renderer) { bool visible = true; GetDataNode()->GetVisibility(visible, renderer, "visible"); if (!visible) return; // @FIXME: Logik fuer update bool updateNeccesary = true; if (updateNeccesary) { // aus GenerateData mitk::Mesh::Pointer input = const_cast(this->GetInput()); // Get the TimeGeometry of the input object const TimeGeometry *inputTimeGeometry = input->GetTimeGeometry(); if ((inputTimeGeometry == nullptr) || (inputTimeGeometry->CountTimeSteps() == 0)) { return; } // // get the world time // ScalarType time = renderer->GetTime(); // // convert the world time in time steps of the input object // int timeStep = 0; if (time > itk::NumericTraits::NonpositiveMin()) timeStep = inputTimeGeometry->TimePointToTimeStep(time); if (inputTimeGeometry->IsValidTimeStep(timeStep) == false) { return; } mitk::Mesh::MeshType::Pointer itkMesh = input->GetMesh(timeStep); if (itkMesh.GetPointer() == nullptr) { return; } const PlaneGeometry *worldplanegeometry = (renderer->GetCurrentWorldPlaneGeometry()); // apply color and opacity read from the PropertyList ApplyColorAndOpacityProperties(renderer); vtkLinearTransform *transform = GetDataNode()->GetVtkTransform(); // List of the Points Mesh::DataType::PointsContainerConstIterator it, end; it = itkMesh->GetPoints()->Begin(); end = itkMesh->GetPoints()->End(); // iterator on the additional data of each point Mesh::PointDataIterator dataIt; //, dataEnd; dataIt = itkMesh->GetPointData()->Begin(); // for switching back to old color after using selected color float unselectedColor[4]; glGetFloatv(GL_CURRENT_COLOR, unselectedColor); while (it != end) { mitk::Point3D p, projected_p; float vtkp[3]; itk2vtk(it->Value(), vtkp); transform->TransformPoint(vtkp, vtkp); vtk2itk(vtkp, p); renderer->GetCurrentWorldPlaneGeometry()->Project(p, projected_p); Vector3D diff = p - projected_p; if (diff.GetSquaredNorm() < 4.0) { Point2D pt2d, tmp; renderer->WorldToDisplay(p, pt2d); Vector2D horz, vert; horz[0] = 5; horz[1] = 0; vert[0] = 0; vert[1] = 5; // check if the point is to be marked as selected if (dataIt->Value().selected) { horz[0] = 8; vert[1] = 8; glColor3f(selectedColor[0], selectedColor[1], selectedColor[2]); // red switch (dataIt->Value().pointSpec) { case PTSTART: - { // a quad glBegin(GL_LINE_LOOP); tmp = pt2d - horz + vert; glVertex2dv(&tmp[0]); tmp = pt2d + horz + vert; glVertex2dv(&tmp[0]); tmp = pt2d + horz - vert; glVertex2dv(&tmp[0]); tmp = pt2d - horz - vert; glVertex2dv(&tmp[0]); glEnd(); - } - break; + break; case PTUNDEFINED: - { // a diamond around the point glBegin(GL_LINE_LOOP); tmp = pt2d - horz; glVertex2dv(&tmp[0]); tmp = pt2d + vert; glVertex2dv(&tmp[0]); tmp = pt2d + horz; glVertex2dv(&tmp[0]); tmp = pt2d - vert; glVertex2dv(&tmp[0]); glEnd(); - } - break; + break; default: break; } // switch // the actual point glBegin(GL_POINTS); tmp = pt2d; glVertex2dv(&tmp[0]); glEnd(); } else // if not selected { - // TODO: check if this is used anywhere, since it never worked before the last fix glColor3f(unselectedColor[0], unselectedColor[1], unselectedColor[2]); switch (dataIt->Value().pointSpec) { case PTSTART: - { // a quad glBegin(GL_LINE_LOOP); tmp = pt2d - horz + vert; glVertex2dv(&tmp[0]); tmp = pt2d + horz + vert; glVertex2dv(&tmp[0]); tmp = pt2d + horz - vert; glVertex2dv(&tmp[0]); tmp = pt2d - horz - vert; glVertex2dv(&tmp[0]); glEnd(); - } + break; case PTUNDEFINED: - { // drawing crosses glBegin(GL_LINES); tmp = pt2d - horz; glVertex2dv(&tmp[0]); tmp = pt2d + horz; glVertex2dv(&tmp[0]); tmp = pt2d - vert; glVertex2dv(&tmp[0]); tmp = pt2d + vert; glVertex2dv(&tmp[0]); glEnd(); - } + break; default: { break; } } // switch } // else } ++it; ++dataIt; } // now connect the lines inbetween mitk::Mesh::PointType thisPoint; thisPoint.Fill(0); Point2D *firstOfCell = nullptr; Point2D *lastPoint = nullptr; unsigned int lastPointId = 0; bool lineSelected = false; Point3D firstOfCell3D; Point3D lastPoint3D; bool first; mitk::Line line; std::vector intersectionPoints; double t; // iterate through all cells and then iterate through all indexes of points in that cell Mesh::CellIterator cellIt, cellEnd; Mesh::CellDataIterator cellDataIt; //, cellDataEnd; Mesh::PointIdIterator cellIdIt, cellIdEnd; cellIt = itkMesh->GetCells()->Begin(); cellEnd = itkMesh->GetCells()->End(); cellDataIt = itkMesh->GetCellData()->Begin(); while (cellIt != cellEnd) { unsigned int numOfPointsInCell = cellIt->Value()->GetNumberOfPoints(); if (numOfPointsInCell > 1) { // iterate through all id's in the cell cellIdIt = cellIt->Value()->PointIdsBegin(); cellIdEnd = cellIt->Value()->PointIdsEnd(); firstOfCell3D = input->GetPoint(*cellIdIt, timeStep); intersectionPoints.clear(); intersectionPoints.reserve(numOfPointsInCell); first = true; while (cellIdIt != cellIdEnd) { lastPoint3D = thisPoint; thisPoint = input->GetPoint(*cellIdIt, timeStep); // search in data (vector<> selectedLines) if the index of the point is set. if so, then the line is selected. lineSelected = false; Mesh::SelectedLinesType selectedLines = cellDataIt->Value().selectedLines; // a line between 1(lastPoint) and 2(pt2d) has the Id 1, so look for the Id of lastPoint // since we only start, if we have more than one point in the cell, lastPointId is initiated with 0 Mesh::SelectedLinesIter position = std::find(selectedLines.begin(), selectedLines.end(), lastPointId); if (position != selectedLines.end()) { lineSelected = true; } mitk::Point3D p, projected_p; float vtkp[3]; itk2vtk(thisPoint, vtkp); transform->TransformPoint(vtkp, vtkp); vtk2itk(vtkp, p); renderer->GetCurrentWorldPlaneGeometry()->Project(p, projected_p); Vector3D diff = p - projected_p; if (diff.GetSquaredNorm() < 4.0) { Point2D pt2d, tmp; renderer->WorldToDisplay(p, pt2d); if (lastPoint == nullptr) { // set the first point in the cell. This point in needed to close the polygon firstOfCell = new Point2D; *firstOfCell = pt2d; lastPoint = new Point2D; *lastPoint = pt2d; lastPointId = *cellIdIt; } else { if (lineSelected) { glColor3f(selectedColor[0], selectedColor[1], selectedColor[2]); // red // a line from lastPoint to thisPoint glBegin(GL_LINES); glVertex2dv(&(*lastPoint)[0]); glVertex2dv(&pt2d[0]); glEnd(); } else // if not selected { glColor3f(unselectedColor[0], unselectedColor[1], unselectedColor[2]); // drawing crosses glBegin(GL_LINES); glVertex2dv(&(*lastPoint)[0]); glVertex2dv(&pt2d[0]); glEnd(); } // to draw the line to the next in iteration step *lastPoint = pt2d; // and to search for the selection state of the line lastPointId = *cellIdIt; } // if..else } // if <4.0 // fill off-plane polygon part 1 if ((!first) && (worldplanegeometry != nullptr)) { line.SetPoints(lastPoint3D, thisPoint); if (worldplanegeometry->IntersectionPointParam(line, t) && ((t >= 0) && (t <= 1))) { intersectionPoints.push_back(line.GetPoint(t)); } } ++cellIdIt; first = false; } // while cellIdIter // closed polygon? if (cellDataIt->Value().closed) { // close the polygon if needed if (firstOfCell != nullptr) { lineSelected = false; Mesh::SelectedLinesType selectedLines = cellDataIt->Value().selectedLines; Mesh::SelectedLinesIter position = std::find(selectedLines.begin(), selectedLines.end(), lastPointId); if (position != selectedLines.end()) // found the index { glColor3f(selectedColor[0], selectedColor[1], selectedColor[2]); // red // a line from lastPoint to firstPoint glBegin(GL_LINES); glVertex2dv(&(*lastPoint)[0]); glVertex2dv(&(*firstOfCell)[0]); glEnd(); } else { glColor3f(unselectedColor[0], unselectedColor[1], unselectedColor[2]); glBegin(GL_LINES); glVertex2dv(&(*lastPoint)[0]); glVertex2dv(&(*firstOfCell)[0]); glEnd(); } } } // if closed // Axis-aligned bounding box(AABB) around the cell if selected and set in Property bool showBoundingBox; if (dynamic_cast(this->GetDataNode()->GetProperty("showBoundingBox")) == nullptr) showBoundingBox = false; else showBoundingBox = dynamic_cast(this->GetDataNode()->GetProperty("showBoundingBox"))->GetValue(); if (showBoundingBox) { if (cellDataIt->Value().selected) { mitk::Mesh::DataType::BoundingBoxPointer aABB = input->GetBoundingBoxFromCell(cellIt->Index()); if (aABB.IsNotNull()) { mitk::Mesh::PointType min, max; min = aABB->GetMinimum(); max = aABB->GetMaximum(); // project to the displayed geometry Point2D min2D, max2D; Point3D p, projected_p; float vtkp[3]; itk2vtk(min, vtkp); transform->TransformPoint(vtkp, vtkp); vtk2itk(vtkp, p); renderer->WorldToDisplay(p, min2D); itk2vtk(max, vtkp); transform->TransformPoint(vtkp, vtkp); vtk2itk(vtkp, p); renderer->GetCurrentWorldPlaneGeometry()->Project(p, projected_p); Vector3D diff = p - projected_p; if (diff.GetSquaredNorm() < 4.0) { renderer->WorldToDisplay(p, max2D); // draw the BoundingBox glColor3f(selectedColor[0], selectedColor[1], selectedColor[2]); // red // a line from lastPoint to firstPoint glBegin(GL_LINE_LOOP); glVertex2f(min2D[0], min2D[1]); glVertex2f(min2D[0], max2D[1]); glVertex2f(max2D[0], max2D[1]); glVertex2f(max2D[0], min2D[1]); glEnd(); } // draw bounding-box } // bounding-box exists } // cell selected } // show bounding-box // fill off-plane polygon part 2 if (worldplanegeometry != nullptr) { // consider line from last to first line.SetPoints(thisPoint, firstOfCell3D); if (worldplanegeometry->IntersectionPointParam(line, t) && ((t >= 0) && (t <= 1))) { intersectionPoints.push_back(line.GetPoint(t)); } std::sort(intersectionPoints.begin(), intersectionPoints.end(), point3DSmaller); std::vector::iterator it, end; end = intersectionPoints.end(); if ((intersectionPoints.size() % 2) != 0) { --end; // ensure even number of intersection-points } Point2D pt2d; for (it = intersectionPoints.begin(); it != end; ++it) { glBegin(GL_LINES); renderer->WorldToDisplay(*it, pt2d); glVertex2dv(pt2d.GetDataPointer()); ++it; renderer->WorldToDisplay(*it, pt2d); glVertex2dv(pt2d.GetDataPointer()); glEnd(); } if (it != intersectionPoints.end()) { glBegin(GL_LINES); renderer->WorldToDisplay(*it, pt2d); glVertex2dv(pt2d.GetDataPointer()); glVertex2dv(pt2d.GetDataPointer()); glEnd(); } } // fill off-plane polygon part 2 } // if numOfPointsInCell>1 delete firstOfCell; delete lastPoint; lastPoint = nullptr; firstOfCell = nullptr; lastPointId = 0; ++cellIt; ++cellDataIt; } } } diff --git a/Modules/PlanarFigure/src/DataManagement/mitkPlanarCross.cpp b/Modules/PlanarFigure/src/DataManagement/mitkPlanarCross.cpp index 8e0f7de0b8..428e2bcf6a 100644 --- a/Modules/PlanarFigure/src/DataManagement/mitkPlanarCross.cpp +++ b/Modules/PlanarFigure/src/DataManagement/mitkPlanarCross.cpp @@ -1,345 +1,335 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPlanarCross.h" #include "mitkPlaneGeometry.h" #include "mitkProperties.h" mitk::PlanarCross::PlanarCross() : FEATURE_ID_LONGESTDIAMETER(this->AddFeature("Longest Axis", "mm")), FEATURE_ID_SHORTAXISDIAMETER(this->AddFeature("Short Axis", "mm")) { // Cross has two control points at the beginning this->ResetNumberOfControlPoints(2); // Create property for SingleLineMode (default: false) this->SetProperty("SingleLineMode", mitk::BoolProperty::New(false)); // Create helper polyline object (for drawing the orthogonal orientation line) this->SetNumberOfHelperPolyLines(1); m_HelperPolyLinesToBePainted->InsertElement(0, false); } void mitk::PlanarCross::SetSingleLineMode(bool singleLineMode) { this->SetProperty("SingleLineMode", mitk::BoolProperty::New(singleLineMode)); this->Modified(); } bool mitk::PlanarCross::GetSingleLineMode() const { const mitk::BoolProperty *singleLineMode = dynamic_cast(this->GetProperty("SingleLineMode").GetPointer()); if (singleLineMode != nullptr) { return singleLineMode->GetValue(); } return false; } bool mitk::PlanarCross::ResetOnPointSelectNeeded() const { return this->GetSingleLineMode() == false || (m_SelectedControlPoint >= 0 && m_SelectedControlPoint <= 3); } bool mitk::PlanarCross::ResetOnPointSelect() { if (this->GetSingleLineMode()) { // In single line mode --> nothing to reset return false; } switch (m_SelectedControlPoint) { default: // Nothing selected --> nothing to reset return false; - case 0: - { // Control point 0 selected: exchange points 0 and 1 - const Point2D tmpPoint = this->GetControlPoint(0); - this->SetControlPoint(0, this->GetControlPoint(1)); - this->SetControlPoint(1, tmpPoint); - // FALLS THROUGH! - } - + { + const Point2D tmpPoint = this->GetControlPoint(0); + this->SetControlPoint(0, this->GetControlPoint(1)); + this->SetControlPoint(1, tmpPoint); + } + // FALLTHRU! case 1: - { // Control point 0 or 1 selected: reset number of control points to two this->ResetNumberOfControlPoints(2); this->SelectControlPoint(1); return true; - } - case 2: - { // Control point 2 selected: replace point 0 with point 3 and point 1 with point 2 this->SetControlPoint(0, this->GetControlPoint(3)); this->SetControlPoint(1, this->GetControlPoint(2)); // Adjust selected control point, reset number of control points to two this->ResetNumberOfControlPoints(2); this->SelectControlPoint(1); return true; - } - case 3: - { // Control point 3 selected: replace point 0 with point 2 and point 1 with point 3 this->SetControlPoint(0, this->GetControlPoint(2)); this->SetControlPoint(1, this->GetControlPoint(3)); // Adjust selected control point, reset number of control points to two this->ResetNumberOfControlPoints(2); this->SelectControlPoint(1); return true; - } } } unsigned int mitk::PlanarCross::GetNumberOfFeatures() const { if (this->GetSingleLineMode() || (this->GetNumberOfControlPoints() < 4)) { return 1; } else { return 2; } } mitk::Point2D mitk::PlanarCross::ApplyControlPointConstraints(unsigned int index, const Point2D &point) { // Apply spatial constraints from superclass and from this class until the resulting constrained // point converges. Although not an optimal implementation, this iterative approach // helps to respect both constraints from the superclass and from this class. Without this, // situations may occur where control points are constrained by the superclass, but again // moved out of the superclass bounds by the subclass, or vice versa. unsigned int count = 0; // ensures stop of approach if point does not converge in reasonable time Point2D confinedPoint = point; Point2D superclassConfinedPoint; do { superclassConfinedPoint = Superclass::ApplyControlPointConstraints(index, confinedPoint); confinedPoint = this->InternalApplyControlPointConstraints(index, superclassConfinedPoint); ++count; } while ((confinedPoint.EuclideanDistanceTo(superclassConfinedPoint) > mitk::eps) && (count < 32)); return confinedPoint; } mitk::Point2D mitk::PlanarCross::InternalApplyControlPointConstraints(unsigned int index, const Point2D &point) { // Apply constraints depending on current interaction state switch (index) { case 2: { // Check if 3rd control point is outside of the range (2D area) defined by the first // line (via the first two control points); if it is outside, clip it to the bounds const Point2D p1 = this->GetControlPoint(0); const Point2D p2 = this->GetControlPoint(1); Vector2D n1 = p2 - p1; n1.Normalize(); const Vector2D v1 = point - p1; const double dotProduct = n1 * v1; const Point2D crossPoint = p1 + n1 * dotProduct; ; const Vector2D crossVector = point - crossPoint; if (dotProduct < 0.0) { // Out-of-bounds on the left: clip point to left boundary return (p1 + crossVector); } else if (dotProduct > p2.EuclideanDistanceTo(p1)) { // Out-of-bounds on the right: clip point to right boundary return (p2 + crossVector); } else { // Pass back original point return point; } } case 3: { // Constrain 4th control point so that with the 3rd control point it forms // a line orthogonal to the first line (constraint 1); the 4th control point // must lie on the opposite side of the line defined by the first two control // points than the 3rd control point (constraint 2) const Point2D p1 = this->GetControlPoint(0); const Point2D p2 = this->GetControlPoint(1); const Point2D p3 = this->GetControlPoint(2); // Calculate distance of original point from orthogonal line the corrected // point should lie on to project the point onto this line Vector2D n1 = p2 - p1; n1.Normalize(); const Vector2D v1 = point - p3; const double dotProduct1 = n1 * v1; const Point2D pointOnLine = point - n1 * dotProduct1; // Project new point onto line [p1, p2] const Vector2D v2 = pointOnLine - p1; double dotProduct2 = n1 * v2; const Point2D crossingPoint = p1 + n1 * dotProduct2; // Determine whether the projected point on the line, or the crossing point should be // used (according to the second constraint in the comment above) if ((pointOnLine.SquaredEuclideanDistanceTo(p3) > crossingPoint.SquaredEuclideanDistanceTo(p3)) && (pointOnLine.SquaredEuclideanDistanceTo(p3) > pointOnLine.SquaredEuclideanDistanceTo(crossingPoint))) { return pointOnLine; } else { return crossingPoint; } } default: return point; } } void mitk::PlanarCross::GeneratePolyLine() { this->SetNumberOfPolyLines(1); this->ClearPolyLines(); if (this->GetNumberOfControlPoints() > 2) this->SetNumberOfPolyLines(2); for (unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i) { if (i < 2) this->AppendPointToPolyLine(0, this->GetControlPoint(i)); if (i > 1) this->AppendPointToPolyLine(1, this->GetControlPoint(i)); } } void mitk::PlanarCross::GenerateHelperPolyLine(double /*mmPerDisplayUnit*/, unsigned int /*displayHeight*/) { // Generate helper polyline (orientation line orthogonal to first line) // if the third control point is currently being set if (this->GetNumberOfControlPoints() != 3) { m_HelperPolyLinesToBePainted->SetElement(0, false); return; } m_HelperPolyLinesToBePainted->SetElement(0, true); this->ClearHelperPolyLines(); // Calculate cross point of first line (p1 to p2) and orthogonal line through // the third control point (p3) const Point2D p1 = this->GetControlPoint(0); const Point2D p2 = this->GetControlPoint(1); const Point2D p3 = this->GetControlPoint(2); Vector2D n1 = p2 - p1; n1.Normalize(); const Vector2D v1 = p3 - p1; const Point2D crossPoint = p1 + n1 * (n1 * v1); const Vector2D v2 = crossPoint - p3; if (v2.GetNorm() < 1.0) { // If third point is on the first line, draw orthogonal "infinite" line // through cross point on line Vector2D v0; v0[0] = n1[1]; v0[1] = -n1[0]; this->AppendPointToHelperPolyLine(0, Point2D(p3 - v0 * 10000.0)); this->AppendPointToHelperPolyLine(0, Point2D(p3 + v0 * 10000.0)); } else { // Else, draw orthogonal line starting from third point and crossing the // first line, open-ended only on the other side this->AppendPointToHelperPolyLine(0, p3); this->AppendPointToHelperPolyLine(0, Point2D(p3 + v2 * 10000.0)); } } void mitk::PlanarCross::EvaluateFeaturesInternal() { // Calculate length of first line const Point3D &p0 = this->GetWorldControlPoint(0); const Point3D &p1 = this->GetWorldControlPoint(1); double l1 = p0.EuclideanDistanceTo(p1); // Calculate length of second line double l2 = 0.0; if (!this->GetSingleLineMode() && (this->GetNumberOfControlPoints() > 3)) { const Point3D &p2 = this->GetWorldControlPoint(2); const Point3D &p3 = this->GetWorldControlPoint(3); l2 = p2.EuclideanDistanceTo(p3); } double longestDiameter; double shortAxisDiameter; if (l1 > l2) { longestDiameter = l1; shortAxisDiameter = l2; } else { longestDiameter = l2; shortAxisDiameter = l1; } this->SetQuantity(FEATURE_ID_LONGESTDIAMETER, longestDiameter); this->SetQuantity(FEATURE_ID_SHORTAXISDIAMETER, shortAxisDiameter); } void mitk::PlanarCross::PrintSelf(std::ostream &os, itk::Indent indent) const { Superclass::PrintSelf(os, indent); } bool mitk::PlanarCross::Equals(const mitk::PlanarFigure &other) const { const mitk::PlanarCross *otherCross = dynamic_cast(&other); if (otherCross) { return Superclass::Equals(other); } else { return false; } } diff --git a/Modules/QtWidgets/src/QmitkPropertiesTableModel.cpp b/Modules/QtWidgets/src/QmitkPropertiesTableModel.cpp index 66dcaf9140..c79d66414c 100644 --- a/Modules/QtWidgets/src/QmitkPropertiesTableModel.cpp +++ b/Modules/QtWidgets/src/QmitkPropertiesTableModel.cpp @@ -1,529 +1,530 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkPropertiesTableModel.h" //# Own includes #include "QmitkCustomVariants.h" #include "mitkColorProperty.h" #include "mitkEnumerationProperty.h" #include "mitkProperties.h" #include "mitkRenderingManager.h" #include "mitkStringProperty.h" //# Toolkit includes #include #include #include #include //# PUBLIC CTORS,DTOR QmitkPropertiesTableModel::QmitkPropertiesTableModel(QObject *parent, mitk::PropertyList::Pointer _PropertyList) : QAbstractTableModel(parent), m_PropertyList(nullptr), m_BlockEvents(false), m_SortDescending(false), m_FilterKeyWord("") { this->SetPropertyList(_PropertyList); } QmitkPropertiesTableModel::~QmitkPropertiesTableModel() { // remove all event listeners by setting the property list to 0 this->SetPropertyList(nullptr); } //# PUBLIC GETTER mitk::PropertyList::Pointer QmitkPropertiesTableModel::GetPropertyList() const { return m_PropertyList.GetPointer(); } Qt::ItemFlags QmitkPropertiesTableModel::flags(const QModelIndex &index) const { // no editing so far, return default (enabled, selectable) Qt::ItemFlags flags = QAbstractItemModel::flags(index); if (index.column() == PROPERTY_VALUE_COLUMN) { // there are also read only property items -> do not allow editing them if (index.data(Qt::EditRole).isValid()) flags |= Qt::ItemIsEditable; if (index.data(Qt::CheckStateRole).isValid()) flags |= Qt::ItemIsUserCheckable; } return flags; } QVariant QmitkPropertiesTableModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) return QVariant(); if (orientation == Qt::Horizontal) { switch (section) { case PROPERTY_NAME_COLUMN: return tr("Name"); case PROPERTY_VALUE_COLUMN: return tr("Value"); default: return QVariant(); } } return QVariant(); } QVariant QmitkPropertiesTableModel::data(const QModelIndex &index, int role) const { // empty data by default QVariant data; if (!index.isValid() || m_SelectedProperties.empty() || index.row() > (int)(m_SelectedProperties.size() - 1)) return data; // the properties name if (index.column() == PROPERTY_NAME_COLUMN) { if (role == Qt::DisplayRole) data = QString::fromStdString(m_SelectedProperties[index.row()].first); } // the real properties value else if (index.column() == PROPERTY_VALUE_COLUMN) { mitk::BaseProperty *baseProp = m_SelectedProperties[index.row()].second; if (const mitk::ColorProperty *colorProp = dynamic_cast(baseProp)) { mitk::Color col = colorProp->GetColor(); QColor qcol((int)(col.GetRed() * 255), (int)(col.GetGreen() * 255), (int)(col.GetBlue() * 255)); if (role == Qt::DisplayRole) data.setValue(qcol); else if (role == Qt::EditRole) data.setValue(qcol); } else if (mitk::BoolProperty *boolProp = dynamic_cast(baseProp)) { if (role == Qt::CheckStateRole) data = boolProp->GetValue() ? Qt::Checked : Qt::Unchecked; } else if (mitk::StringProperty *stringProp = dynamic_cast(baseProp)) { if (role == Qt::DisplayRole) data.setValue(QString::fromStdString(stringProp->GetValue())); else if (role == Qt::EditRole) data.setValue(QString::fromStdString(stringProp->GetValue())); } else if (mitk::IntProperty *intProp = dynamic_cast(baseProp)) { if (role == Qt::DisplayRole) data.setValue(intProp->GetValue()); else if (role == Qt::EditRole) data.setValue(intProp->GetValue()); } else if (mitk::FloatProperty *floatProp = dynamic_cast(baseProp)) { if (role == Qt::DisplayRole) data.setValue(floatProp->GetValue()); else if (role == Qt::EditRole) data.setValue(floatProp->GetValue()); } else if (mitk::EnumerationProperty *enumerationProp = dynamic_cast(baseProp)) { if (role == Qt::DisplayRole) data.setValue(QString::fromStdString(baseProp->GetValueAsString())); else if (role == Qt::EditRole) { QStringList values; for (auto it = enumerationProp->Begin(); it != enumerationProp->End(); it++) { values << QString::fromStdString(it->second); } data.setValue(values); } } else { if (role == Qt::DisplayRole) data.setValue(QString::fromStdString(m_SelectedProperties[index.row()].second->GetValueAsString())); } } return data; } int QmitkPropertiesTableModel::rowCount(const QModelIndex & /*parent*/) const { // return the number of properties in the properties list. return m_SelectedProperties.size(); } int QmitkPropertiesTableModel::columnCount(const QModelIndex & /*parent*/) const { return 2; } //# PUBLIC SETTER void QmitkPropertiesTableModel::SetPropertyList(mitk::PropertyList *_PropertyList) { // if propertylist really changed if (m_PropertyList.GetPointer() != _PropertyList) { // Remove delete listener if there was a propertylist before if (m_PropertyList.IsNotNull()) { m_PropertyList.ObjectDelete.RemoveListener(mitk::MessageDelegate1( this, &QmitkPropertiesTableModel::PropertyListDelete)); } // set new list m_PropertyList = _PropertyList; if (m_PropertyList.IsNotNull()) { m_PropertyList.ObjectDelete.AddListener(mitk::MessageDelegate1( this, &QmitkPropertiesTableModel::PropertyListDelete)); } this->Reset(); } } void QmitkPropertiesTableModel::PropertyListDelete(const itk::Object * /*_PropertyList*/) { if (!m_BlockEvents) { m_BlockEvents = true; this->Reset(); m_BlockEvents = false; } } void QmitkPropertiesTableModel::PropertyModified(const itk::Object *caller, const itk::EventObject & /*event*/) { if (!m_BlockEvents) { m_BlockEvents = true; int row = this->FindProperty(dynamic_cast(caller)); QModelIndex indexOfChangedProperty = index(row, 1); emit dataChanged(indexOfChangedProperty, indexOfChangedProperty); m_BlockEvents = false; } } void QmitkPropertiesTableModel::PropertyDelete(const itk::Object *caller, const itk::EventObject & /*event*/) { if (!m_BlockEvents) { m_BlockEvents = true; int row = this->FindProperty(dynamic_cast(caller)); if (row >= 0) this->Reset(); m_BlockEvents = false; } } bool QmitkPropertiesTableModel::setData(const QModelIndex &index, const QVariant &value, int role) { + // TODO: check 'role' condition if (index.isValid() && !m_SelectedProperties.empty() && index.row() < (int)(m_SelectedProperties.size()) && - (role == Qt::EditRole || Qt::CheckStateRole)) + (role == Qt::EditRole || role == Qt::CheckStateRole)) { // block all events now! m_BlockEvents = true; // the properties name if (index.column() == PROPERTY_VALUE_COLUMN) { mitk::BaseProperty *baseProp = m_SelectedProperties[index.row()].second; if (mitk::ColorProperty *colorProp = dynamic_cast(baseProp)) { QColor qcolor = value.value(); if (!qcolor.isValid()) return false; mitk::Color col = colorProp->GetColor(); col.SetRed(qcolor.red() / 255.0); col.SetGreen(qcolor.green() / 255.0); col.SetBlue(qcolor.blue() / 255.0); colorProp->SetColor(col); m_PropertyList->InvokeEvent(itk::ModifiedEvent()); m_PropertyList->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if (mitk::BoolProperty *boolProp = dynamic_cast(baseProp)) { boolProp->SetValue(value.toInt() == Qt::Checked ? true : false); m_PropertyList->InvokeEvent(itk::ModifiedEvent()); m_PropertyList->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if (mitk::StringProperty *stringProp = dynamic_cast(baseProp)) { stringProp->SetValue((value.value()).toStdString()); m_PropertyList->InvokeEvent(itk::ModifiedEvent()); m_PropertyList->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if (mitk::IntProperty *intProp = dynamic_cast(baseProp)) { int intValue = value.value(); if (intValue != intProp->GetValue()) { intProp->SetValue(intValue); m_PropertyList->InvokeEvent(itk::ModifiedEvent()); m_PropertyList->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } else if (mitk::FloatProperty *floatProp = dynamic_cast(baseProp)) { float floatValue = value.value(); if (floatValue != floatProp->GetValue()) { floatProp->SetValue(floatValue); m_PropertyList->InvokeEvent(itk::ModifiedEvent()); m_PropertyList->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } else if (mitk::EnumerationProperty *enumerationProp = dynamic_cast(baseProp)) { std::string activatedItem = value.value().toStdString(); if (activatedItem != enumerationProp->GetValueAsString()) { if (enumerationProp->IsValidEnumerationValue(activatedItem)) { enumerationProp->SetValue(activatedItem); m_PropertyList->InvokeEvent(itk::ModifiedEvent()); m_PropertyList->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } } } // property was changed by us, now we can accept property changes triggered by someone else m_BlockEvents = false; emit dataChanged(index, index); return true; } return false; } void QmitkPropertiesTableModel::sort(int column, Qt::SortOrder order /*= Qt::AscendingOrder */) { bool sortDescending = (order == Qt::DescendingOrder) ? true : false; // do not sort twice !!! (dont know why, but qt calls this func twice. STUPID!) if (sortDescending != m_SortDescending) { m_SortDescending = sortDescending; PropertyDataSetCompareFunction::CompareCriteria _CompareCriteria = PropertyDataSetCompareFunction::CompareByName; PropertyDataSetCompareFunction::CompareOperator _CompareOperator = m_SortDescending ? PropertyDataSetCompareFunction::Greater : PropertyDataSetCompareFunction::Less; if (column == PROPERTY_VALUE_COLUMN) _CompareCriteria = PropertyDataSetCompareFunction::CompareByValue; PropertyDataSetCompareFunction compareFunc(_CompareCriteria, _CompareOperator); std::sort(m_SelectedProperties.begin(), m_SelectedProperties.end(), compareFunc); QAbstractTableModel::beginResetModel(); QAbstractTableModel::endResetModel(); } } //# PROTECTED GETTER int QmitkPropertiesTableModel::FindProperty(const mitk::BaseProperty *_Property) const { int row = -1; if (_Property) { // search for property that changed and emit datachanged on the corresponding ModelIndex std::vector::const_iterator propertyIterator; for (propertyIterator = m_SelectedProperties.begin(); propertyIterator != m_SelectedProperties.end(); propertyIterator++) { if (propertyIterator->second == _Property) break; } if (propertyIterator != m_SelectedProperties.end()) row = std::distance(m_SelectedProperties.begin(), propertyIterator); } return row; } //# PROTECTED SETTER void QmitkPropertiesTableModel::AddSelectedProperty(PropertyDataSet &_PropertyDataSet) { // subscribe for modified event itk::MemberCommand::Pointer _PropertyDataSetModifiedCommand = itk::MemberCommand::New(); _PropertyDataSetModifiedCommand->SetCallbackFunction(this, &QmitkPropertiesTableModel::PropertyModified); m_PropertyModifiedObserverTags.push_back( _PropertyDataSet.second->AddObserver(itk::ModifiedEvent(), _PropertyDataSetModifiedCommand)); // subscribe for delete event itk::MemberCommand::Pointer _PropertyDataSetDeleteCommand = itk::MemberCommand::New(); _PropertyDataSetDeleteCommand->SetCallbackFunction(this, &QmitkPropertiesTableModel::PropertyDelete); m_PropertyDeleteObserverTags.push_back( _PropertyDataSet.second->AddObserver(itk::DeleteEvent(), _PropertyDataSetDeleteCommand)); // add to the selection m_SelectedProperties.push_back(_PropertyDataSet); } void QmitkPropertiesTableModel::RemoveSelectedProperty(unsigned int _Index) { PropertyDataSet &_PropertyDataSet = m_SelectedProperties.at(_Index); // remove modified event listener _PropertyDataSet.second->RemoveObserver(m_PropertyModifiedObserverTags[_Index]); m_PropertyModifiedObserverTags.erase(m_PropertyModifiedObserverTags.begin() + _Index); // remove delete event listener _PropertyDataSet.second->RemoveObserver(m_PropertyDeleteObserverTags[_Index]); m_PropertyDeleteObserverTags.erase(m_PropertyDeleteObserverTags.begin() + _Index); // remove from selection m_SelectedProperties.erase(m_SelectedProperties.begin() + _Index); } void QmitkPropertiesTableModel::Reset() { // remove all selected properties while (!m_SelectedProperties.empty()) { this->RemoveSelectedProperty(m_SelectedProperties.size() - 1); } std::vector allPredicates; if (m_PropertyList.IsNotNull()) { // first of all: collect all properties from the list for (auto it = m_PropertyList->GetMap()->begin(); it != m_PropertyList->GetMap()->end(); it++) { allPredicates.push_back(*it); //% TODO } } // make a subselection if a keyword is specified if (!m_FilterKeyWord.empty()) { std::vector subSelection; for (auto it = allPredicates.begin(); it != allPredicates.end(); it++) { // add this to the selection if it is matched by the keyword if ((*it).first.find(m_FilterKeyWord) != std::string::npos) subSelection.push_back((*it)); } allPredicates.clear(); allPredicates = subSelection; } PropertyDataSet tmpPropertyDataSet; // add all selected now to the Model for (auto it = allPredicates.begin(); it != allPredicates.end(); it++) { tmpPropertyDataSet = *it; this->AddSelectedProperty(tmpPropertyDataSet); } // sort the list as indicated by m_SortDescending this->sort(m_SortDescending); // model was resetted QAbstractTableModel::beginResetModel(); QAbstractTableModel::endResetModel(); } void QmitkPropertiesTableModel::SetFilterPropertiesKeyWord(std::string _FilterKeyWord) { m_FilterKeyWord = _FilterKeyWord; this->Reset(); } QmitkPropertiesTableModel::PropertyDataSetCompareFunction::PropertyDataSetCompareFunction( CompareCriteria _CompareCriteria, CompareOperator _CompareOperator) : m_CompareCriteria(_CompareCriteria), m_CompareOperator(_CompareOperator) { } bool QmitkPropertiesTableModel::PropertyDataSetCompareFunction::operator()(const PropertyDataSet &_Left, const PropertyDataSet &_Right) const { switch (m_CompareCriteria) { case CompareByValue: if (m_CompareOperator == Less) return (_Left.second->GetValueAsString() < _Right.second->GetValueAsString()); else return (_Left.second->GetValueAsString() > _Right.second->GetValueAsString()); break; // CompareByName: default: if (m_CompareOperator == Less) return (_Left.first < _Right.first); else return (_Left.first > _Right.first); break; } } QmitkPropertiesTableModel::PropertyListElementFilterFunction::PropertyListElementFilterFunction( const std::string &_FilterKeyWord) : m_FilterKeyWord(_FilterKeyWord) { } bool QmitkPropertiesTableModel::PropertyListElementFilterFunction::operator()(const PropertyDataSet &_Elem) const { if (m_FilterKeyWord.empty()) return true; return (_Elem.first.find(m_FilterKeyWord) == 0); } diff --git a/Modules/Segmentation/Algorithms/mitkVtkImageOverwrite.cpp b/Modules/Segmentation/Algorithms/mitkVtkImageOverwrite.cpp index 761b0652fb..ed5215b139 100644 --- a/Modules/Segmentation/Algorithms/mitkVtkImageOverwrite.cpp +++ b/Modules/Segmentation/Algorithms/mitkVtkImageOverwrite.cpp @@ -1,884 +1,887 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*========================================================================= Program: Visualization Toolkit Module: mitkVtkImageOverwrite.cpp Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm 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 notice for more information. =========================================================================*/ #include "mitkVtkImageOverwrite.h" #include "vtkDataSetAttributes.h" #include "vtkGarbageCollector.h" #include "vtkImageData.h" #include "vtkImageStencilData.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkTransform.h" #include "vtkTemplateAliasMacro.h" // turn off 64-bit ints when templating over all types #undef VTK_USE_INT64 #define VTK_USE_INT64 0 #undef VTK_USE_UINT64 #define VTK_USE_UINT64 0 #include #include #include vtkStandardNewMacro(mitkVtkImageOverwrite); //-------------------------------------------------------------------------- // The 'floor' function on x86 and mips is many times slower than these // and is used a lot in this code, optimize for different CPU architectures template inline int vtkResliceFloor(double x, F &f) { #if defined mips || defined sparc || defined __ppc__ x += 2147483648.0; unsigned int i = static_cast(x); f = x - i; return static_cast(i - 2147483648U); #elif defined i386 || defined _M_IX86 union { double d; unsigned short s[4]; unsigned int i[2]; } dual; dual.d = x + 103079215104.0; // (2**(52-16))*1.5 f = dual.s[0] * 0.0000152587890625; // 2**(-16) return static_cast((dual.i[1] << 16) | ((dual.i[0]) >> 16)); #elif defined ia64 || defined __ia64__ || defined IA64 x += 103079215104.0; long long i = static_cast(x); f = x - i; return static_cast(i - 103079215104LL); #else double y = floor(x); f = x - y; return static_cast(y); #endif } inline int vtkResliceRound(double x) { #if defined mips || defined sparc || defined __ppc__ return static_cast(static_cast(x + 2147483648.5) - 2147483648U); #elif defined i386 || defined _M_IX86 union { double d; unsigned int i[2]; } dual; dual.d = x + 103079215104.5; // (2**(52-16))*1.5 return static_cast((dual.i[1] << 16) | ((dual.i[0]) >> 16)); #elif defined ia64 || defined __ia64__ || defined IA64 x += 103079215104.5; long long i = static_cast(x); return static_cast(i - 103079215104LL); #else return static_cast(floor(x + 0.5)); #endif } //---------------------------------------------------------------------------- mitkVtkImageOverwrite::mitkVtkImageOverwrite() { m_Overwrite_Mode = false; this->GetOutput()->AllocateScalars(VTK_UNSIGNED_INT, 1); // VTK6_TODO where should the image be allocated? } //---------------------------------------------------------------------------- mitkVtkImageOverwrite::~mitkVtkImageOverwrite() { } //---------------------------------------------------------------------------- // constants for different boundary-handling modes #define VTK_RESLICE_BACKGROUND 0 // use background if out-of-bounds #define VTK_RESLICE_WRAP 1 // wrap to opposite side of image #define VTK_RESLICE_MIRROR 2 // mirror off of the boundary #define VTK_RESLICE_BORDER 3 // use a half-voxel border #define VTK_RESLICE_nullptr 4 // do nothing to *outPtr if out-of-bounds //---------------------------------------------------------------------------- // rounding functions for each type, where 'F' is a floating-point type #if (VTK_USE_INT8 != 0) template inline void vtkResliceRound(F val, vtkTypeInt8 &rnd) { rnd = vtkResliceRound(val); } #endif #if (VTK_USE_UINT8 != 0) template inline void vtkResliceRound(F val, vtkTypeUInt8 &rnd) { rnd = vtkResliceRound(val); } #endif #if (VTK_USE_INT16 != 0) template inline void vtkResliceRound(F val, vtkTypeInt16 &rnd) { rnd = vtkResliceRound(val); } #endif #if (VTK_USE_UINT16 != 0) template inline void vtkResliceRound(F val, vtkTypeUInt16 &rnd) { rnd = vtkResliceRound(val); } #endif #if (VTK_USE_INT32 != 0) template inline void vtkResliceRound(F val, vtkTypeInt32 &rnd) { rnd = vtkResliceRound(val); } #endif #if (VTK_USE_UINT32 != 0) template inline void vtkResliceRound(F val, vtkTypeUInt32 &rnd) { rnd = vtkResliceRound(val); } #endif #if (VTK_USE_FLOAT32 != 0) template inline void vtkResliceRound(F val, vtkTypeFloat32 &rnd) { rnd = val; } #endif #if (VTK_USE_FLOAT64 != 0) template inline void vtkResliceRound(F val, vtkTypeFloat64 &rnd) { rnd = val; } #endif //---------------------------------------------------------------------------- // clamping functions for each type #if (VTK_USE_INT8 != 0) template inline void vtkResliceClamp(F val, vtkTypeInt8 &clamp) { if (val < -128.0) { val = -128.0; } if (val > 127.0) { val = 127.0; } vtkResliceRound(val, clamp); } #endif #if (VTK_USE_UINT8 != 0) template inline void vtkResliceClamp(F val, vtkTypeUInt8 &clamp) { if (val < 0) { val = 0; } if (val > 255.0) { val = 255.0; } vtkResliceRound(val, clamp); } #endif #if (VTK_USE_INT16 != 0) template inline void vtkResliceClamp(F val, vtkTypeInt16 &clamp) { if (val < -32768.0) { val = -32768.0; } if (val > 32767.0) { val = 32767.0; } vtkResliceRound(val, clamp); } #endif #if (VTK_USE_UINT16 != 0) template inline void vtkResliceClamp(F val, vtkTypeUInt16 &clamp) { if (val < 0) { val = 0; } if (val > 65535.0) { val = 65535.0; } vtkResliceRound(val, clamp); } #endif #if (VTK_USE_INT32 != 0) template inline void vtkResliceClamp(F val, vtkTypeInt32 &clamp) { if (val < -2147483648.0) { val = -2147483648.0; } if (val > 2147483647.0) { val = 2147483647.0; } vtkResliceRound(val, clamp); } #endif #if (VTK_USE_UINT32 != 0) template inline void vtkResliceClamp(F val, vtkTypeUInt32 &clamp) { if (val < 0) { val = 0; } if (val > 4294967295.0) { val = 4294967295.0; } vtkResliceRound(val, clamp); } #endif #if (VTK_USE_FLOAT32 != 0) template inline void vtkResliceClamp(F val, vtkTypeFloat32 &clamp) { clamp = val; } #endif #if (VTK_USE_FLOAT64 != 0) template inline void vtkResliceClamp(F val, vtkTypeFloat64 &clamp) { clamp = val; } #endif //---------------------------------------------------------------------------- // Perform a wrap to limit an index to [0,range). // Ensures correct behaviour when the index is negative. inline int vtkInterpolateWrap(int num, int range) { if ((num %= range) < 0) { num += range; // required for some % implementations } return num; } //---------------------------------------------------------------------------- // Perform a mirror to limit an index to [0,range). inline int vtkInterpolateMirror(int num, int range) { if (num < 0) { num = -num - 1; } int count = num / range; num %= range; if (count & 0x1) { num = range - num - 1; } return num; } //---------------------------------------------------------------------------- // If the value is within one half voxel of the range [0,inExtX), then // set it to "0" or "inExtX-1" as appropriate. inline int vtkInterpolateBorder(int &inIdX0, int &inIdX1, int inExtX, double fx) { if (inIdX0 >= 0 && inIdX1 < inExtX) { return 0; } if (inIdX0 == -1 && fx >= 0.5) { inIdX1 = inIdX0 = 0; return 0; } if (inIdX0 == inExtX - 1 && fx < 0.5) { inIdX1 = inIdX0; return 0; } return 1; } inline int vtkInterpolateBorderCheck(int inIdX0, int inIdX1, int inExtX, double fx) { if ((inIdX0 >= 0 && inIdX1 < inExtX) || (inIdX0 == -1 && fx >= 0.5) || (inIdX0 == inExtX - 1 && fx < 0.5)) { return 0; } return 1; } //---------------------------------------------------------------------------- // Do nearest-neighbor interpolation of the input data 'inPtr' of extent // 'inExt' at the 'point'. The result is placed at 'outPtr'. // If the lookup data is beyond the extent 'inExt', set 'outPtr' to // the background color 'background'. // The number of scalar components in the data is 'numscalars' template static int vtkNearestNeighborInterpolation(T *&outPtr, const T *inPtr, const int inExt[6], const vtkIdType inInc[3], int numscalars, const F point[3], int mode, const T *background, mitkVtkImageOverwrite *self) { int inIdX0 = vtkResliceRound(point[0]) - inExt[0]; int inIdY0 = vtkResliceRound(point[1]) - inExt[2]; int inIdZ0 = vtkResliceRound(point[2]) - inExt[4]; int inExtX = inExt[1] - inExt[0] + 1; int inExtY = inExt[3] - inExt[2] + 1; int inExtZ = inExt[5] - inExt[4] + 1; if (inIdX0 < 0 || inIdX0 >= inExtX || inIdY0 < 0 || inIdY0 >= inExtY || inIdZ0 < 0 || inIdZ0 >= inExtZ) { if (mode == VTK_RESLICE_WRAP) { inIdX0 = vtkInterpolateWrap(inIdX0, inExtX); inIdY0 = vtkInterpolateWrap(inIdY0, inExtY); inIdZ0 = vtkInterpolateWrap(inIdZ0, inExtZ); } else if (mode == VTK_RESLICE_MIRROR) { inIdX0 = vtkInterpolateMirror(inIdX0, inExtX); inIdY0 = vtkInterpolateMirror(inIdY0, inExtY); inIdZ0 = vtkInterpolateMirror(inIdZ0, inExtZ); } else if (mode == VTK_RESLICE_BACKGROUND || mode == VTK_RESLICE_BORDER) { do { *outPtr++ = *background++; } while (--numscalars); return 0; } else { return 0; } } inPtr += inIdX0 * inInc[0] + inIdY0 * inInc[1] + inIdZ0 * inInc[2]; do { if (!self->IsOverwriteMode()) { // just copy from input to output *outPtr++ = *inPtr++; } else { // copy from output to input in overwrite mode *(const_cast(inPtr)) = *outPtr++; inPtr++; } } while (--numscalars); return 1; } //-------------------------------------------------------------------------- // get appropriate interpolation function according to scalar type template static void vtkGetResliceInterpFunc(mitkVtkImageOverwrite *self, int (**interpolate)(void *&outPtr, const void *inPtr, const int inExt[6], const vtkIdType inInc[3], int numscalars, const F point[3], int mode, const void *background, mitkVtkImageOverwrite *self)) { int dataType = self->GetOutput()->GetScalarType(); switch (dataType) { vtkTemplateAliasMacro(*((int (**)(VTK_TT * &outPtr, const VTK_TT *inPtr, const int inExt[6], const vtkIdType inInc[3], int numscalars, const F point[3], int mode, const VTK_TT *background, mitkVtkImageOverwrite *self))interpolate) = &vtkNearestNeighborInterpolation); default: interpolate = nullptr; } } //---------------------------------------------------------------------------- // Some helper functions for 'RequestData' //---------------------------------------------------------------------------- //-------------------------------------------------------------------------- // pixel copy function, templated for different scalar types template struct vtkImageResliceSetPixels { static void Set(void *&outPtrV, const void *inPtrV, int numscalars, int n) { const T *inPtr = static_cast(inPtrV); T *outPtr = static_cast(outPtrV); for (int i = 0; i < n; i++) { const T *tmpPtr = inPtr; int m = numscalars; do { *outPtr++ = *tmpPtr++; } while (--m); } outPtrV = outPtr; } // optimized for 1 scalar components static void Set1(void *&outPtrV, const void *inPtrV, int vtkNotUsed(numscalars), int n) { const T *inPtr = static_cast(inPtrV); T *outPtr = static_cast(outPtrV); T val = *inPtr; for (int i = 0; i < n; i++) { *outPtr++ = val; } outPtrV = outPtr; } }; // get a pixel copy function that is appropriate for the data type static void vtkGetSetPixelsFunc(mitkVtkImageOverwrite *self, void (**setpixels)(void *&out, const void *in, int numscalars, int n)) { int dataType = self->GetOutput()->GetScalarType(); int numscalars = self->GetOutput()->GetNumberOfScalarComponents(); + // TODO: this switch should be examined switch (numscalars) { case 1: switch (dataType) { vtkTemplateAliasMacro(*setpixels = &vtkImageResliceSetPixels::Set1); default: setpixels = nullptr; } + // just to make the compiler happy, TODO: check! + // FALLTHRU default: switch (dataType) { vtkTemplateAliasMacro(*setpixels = &vtkImageResliceSetPixels::Set); default: setpixels = nullptr; } } } //---------------------------------------------------------------------------- // Convert background color from float to appropriate type template static void vtkAllocBackgroundPixelT(mitkVtkImageOverwrite *self, T **background_ptr, int numComponents) { *background_ptr = new T[numComponents]; T *background = *background_ptr; for (int i = 0; i < numComponents; i++) { if (i < 4) { vtkResliceClamp(self->GetBackgroundColor()[i], background[i]); } else { background[i] = 0; } } } static void vtkAllocBackgroundPixel(mitkVtkImageOverwrite *self, void **rval, int numComponents) { switch (self->GetOutput()->GetScalarType()) { vtkTemplateAliasMacro(vtkAllocBackgroundPixelT(self, (VTK_TT **)rval, numComponents)); } } static void vtkFreeBackgroundPixel(mitkVtkImageOverwrite *self, void **rval) { switch (self->GetOutput()->GetScalarType()) { vtkTemplateAliasMacro(delete[] * ((VTK_TT **)rval)); } *rval = nullptr; } //---------------------------------------------------------------------------- // helper function for clipping of the output with a stencil static int vtkResliceGetNextExtent(vtkImageStencilData *stencil, int &r1, int &r2, int rmin, int rmax, int yIdx, int zIdx, void *&outPtr, void *background, int numscalars, void (*setpixels)(void *&out, const void *in, int numscalars, int n), int &iter) { // trivial case if stencil is not set if (!stencil) { if (iter++ == 0) { r1 = rmin; r2 = rmax; return 1; } return 0; } // for clearing, start at last r2 plus 1 int clear1 = r2 + 1; if (iter == 0) { // if no 'last time', start at rmin clear1 = rmin; } int rval = stencil->GetNextExtent(r1, r2, rmin, rmax, yIdx, zIdx, iter); int clear2 = r1 - 1; if (rval == 0) { clear2 = rmax; } setpixels(outPtr, background, numscalars, clear2 - clear1 + 1); return rval; } //---------------------------------------------------------------------------- // This function simply clears the entire output to the background color, // for cases where the transformation places the output extent completely // outside of the input extent. static void vtkImageResliceClearExecute( mitkVtkImageOverwrite *self, vtkImageData *, void *, vtkImageData *outData, void *outPtr, int outExt[6], int id) { int numscalars; int idY, idZ; vtkIdType outIncX, outIncY, outIncZ; int scalarSize; unsigned long count = 0; unsigned long target; void *background; void (*setpixels)(void *&out, const void *in, int numscalars, int n); // for the progress meter target = static_cast((outExt[5] - outExt[4] + 1) * (outExt[3] - outExt[2] + 1) / 50.0); target++; // Get Increments to march through data outData->GetContinuousIncrements(outExt, outIncX, outIncY, outIncZ); scalarSize = outData->GetScalarSize(); numscalars = outData->GetNumberOfScalarComponents(); // allocate a voxel to copy into the background (out-of-bounds) regions vtkAllocBackgroundPixel(self, &background, numscalars); // get the appropriate function for pixel copying vtkGetSetPixelsFunc(self, &setpixels); // Loop through output voxels for (idZ = outExt[4]; idZ <= outExt[5]; idZ++) { for (idY = outExt[2]; idY <= outExt[3]; idY++) { if (id == 0) { // update the progress if this is the main thread if (!(count % target)) { self->UpdateProgress(count / (50.0 * target)); } count++; } // clear the pixels to background color and go to next row setpixels(outPtr, background, numscalars, outExt[1] - outExt[0] + 1); outPtr = static_cast(static_cast(outPtr) + outIncY * scalarSize); } outPtr = static_cast(static_cast(outPtr) + outIncZ * scalarSize); } vtkFreeBackgroundPixel(self, &background); } //---------------------------------------------------------------------------- // This function executes the filter for any type of data. It is much simpler // in structure than vtkImageResliceOptimizedExecute. static void vtkImageResliceExecute(mitkVtkImageOverwrite *self, vtkImageData *inData, void *inPtr, vtkImageData *outData, void *outPtr, int outExt[6], int id) { int numscalars; int idX, idY, idZ; int idXmin, idXmax, iter; vtkIdType outIncX, outIncY, outIncZ; int scalarSize; int inExt[6]; vtkIdType inInc[3]; unsigned long count = 0; unsigned long target; double point[4]; double f; double *inSpacing, *inOrigin, *outSpacing, *outOrigin, inInvSpacing[3]; void *background; int (*interpolate)(void *&outPtr, const void *inPtr, const int inExt[6], const vtkIdType inInc[3], int numscalars, const double point[3], int mode, const void *background, mitkVtkImageOverwrite *self) = nullptr; void (*setpixels)(void *&out, const void *in, int numscalars, int n) = nullptr; // the 'mode' species what to do with the 'pad' (out-of-bounds) area int mode = VTK_RESLICE_BACKGROUND; if (self->GetMirror()) { mode = VTK_RESLICE_MIRROR; } else if (self->GetWrap()) { mode = VTK_RESLICE_WRAP; } else if (self->GetBorder()) { mode = VTK_RESLICE_BORDER; } // the transformation to apply to the data vtkAbstractTransform *transform = self->GetResliceTransform(); vtkMatrix4x4 *matrix = self->GetResliceAxes(); // for conversion to data coordinates inOrigin = inData->GetOrigin(); inSpacing = inData->GetSpacing(); outOrigin = outData->GetOrigin(); outSpacing = outData->GetSpacing(); // save effor later: invert inSpacing inInvSpacing[0] = 1.0 / inSpacing[0]; inInvSpacing[1] = 1.0 / inSpacing[1]; inInvSpacing[2] = 1.0 / inSpacing[2]; // find maximum input range inData->GetExtent(inExt); // for the progress meter target = static_cast((outExt[5] - outExt[4] + 1) * (outExt[3] - outExt[2] + 1) / 50.0); target++; // Get Increments to march through data inData->GetIncrements(inInc); outData->GetContinuousIncrements(outExt, outIncX, outIncY, outIncZ); scalarSize = outData->GetScalarSize(); numscalars = inData->GetNumberOfScalarComponents(); // allocate a voxel to copy into the background (out-of-bounds) regions vtkAllocBackgroundPixel(self, &background, numscalars); // get the appropriate functions for interpolation and pixel copying vtkGetResliceInterpFunc(self, &interpolate); vtkGetSetPixelsFunc(self, &setpixels); // get the stencil vtkImageStencilData *stencil = self->GetStencil(); // Loop through output voxels for (idZ = outExt[4]; idZ <= outExt[5]; idZ++) { for (idY = outExt[2]; idY <= outExt[3]; idY++) { if (id == 0) { // update the progress if this is the main thread if (!(count % target)) { self->UpdateProgress(count / (50.0 * target)); } count++; } iter = 0; // if there is a stencil, it is applied here while (vtkResliceGetNextExtent( stencil, idXmin, idXmax, outExt[0], outExt[1], idY, idZ, outPtr, background, numscalars, setpixels, iter)) { for (idX = idXmin; idX <= idXmax; idX++) { // convert to data coordinates point[0] = idX * outSpacing[0] + outOrigin[0]; point[1] = idY * outSpacing[1] + outOrigin[1]; point[2] = idZ * outSpacing[2] + outOrigin[2]; // apply ResliceAxes matrix if (matrix) { point[3] = 1.0; matrix->MultiplyPoint(point, point); f = 1.0 / point[3]; point[0] *= f; point[1] *= f; point[2] *= f; } // apply ResliceTransform if (transform) { transform->InternalTransformPoint(point, point); } // convert back to voxel indices point[0] = (point[0] - inOrigin[0]) * inInvSpacing[0]; point[1] = (point[1] - inOrigin[1]) * inInvSpacing[1]; point[2] = (point[2] - inOrigin[2]) * inInvSpacing[2]; // interpolate output voxel from input data set interpolate(outPtr, inPtr, inExt, inInc, numscalars, point, mode, background, self); } } outPtr = static_cast(static_cast(outPtr) + outIncY * scalarSize); } outPtr = static_cast(static_cast(outPtr) + outIncZ * scalarSize); } vtkFreeBackgroundPixel(self, &background); } void mitkVtkImageOverwrite::SetOverwriteMode(bool b) { m_Overwrite_Mode = b; } void mitkVtkImageOverwrite::SetInputSlice(vtkImageData *slice) { // set the output as input this->SetOutput(slice); } //---------------------------------------------------------------------------- // This method is passed a input and output region, and executes the filter // algorithm to fill the output from the input or vice versa. void mitkVtkImageOverwrite::ThreadedRequestData(vtkInformation *vtkNotUsed(request), vtkInformationVector **vtkNotUsed(inputVector), vtkInformationVector *vtkNotUsed(outputVector), vtkImageData ***inData, vtkImageData **outData, int outExt[6], int id) { vtkDebugMacro(<< "Execute: inData = " << inData[0][0] << ", outData = " << outData[0]); // this filter expects that input is the same type as output. if (inData[0][0]->GetScalarType() != outData[0]->GetScalarType()) { vtkErrorMacro(<< "Execute: input ScalarType, " << inData[0][0]->GetScalarType() << ", must match out ScalarType " << outData[0]->GetScalarType()); return; } int inExt[6]; inData[0][0]->GetExtent(inExt); // check for empty input extent if (inExt[1] < inExt[0] || inExt[3] < inExt[2] || inExt[5] < inExt[4]) { return; } // Get the output pointer void *outPtr = outData[0]->GetScalarPointerForExtent(outExt); if (this->HitInputExtent == 0) { vtkImageResliceClearExecute(this, inData[0][0], nullptr, outData[0], outPtr, outExt, id); return; } // Now that we know that we need the input, get the input pointer void *inPtr = inData[0][0]->GetScalarPointerForExtent(inExt); vtkImageResliceExecute(this, inData[0][0], inPtr, outData[0], outPtr, outExt, id); }