/*========================================================================= medInria Copyright (c) INRIA 2013 - 2018. All rights reserved. See LICENSE.txt for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. =========================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class medPaintCommandPrivate { public: QVector3D lastVup; QVector3D lastVpn; double sampleSpacing[2]; LabelObjectType::Pointer label; LabelMapType::Pointer labelMap; typedef itk::LabelMapToAttributeImageFilter< LabelMapType, MaskType > MapToImageFilter; MapToImageFilter::Pointer filter; }; medPaintCommand::medPaintCommand(medPaintCommandOptions *options, QUndoCommand *parent) : medAbstractPaintCommand(options, parent), d(new medPaintCommandPrivate) { d->lastVup = QVector3D(); d->lastVpn = QVector3D(); d->label = 0; this->setText("Paint"); d->labelMap = medPaintCommandManager::instance()->labelMap(this->options()->itkMask); } medPaintCommand::~medPaintCommand() { delete d; d = 0; } void medPaintCommand::paint() { d->label = LabelObjectType::New(); d->label->SetAttribute(this->options()->maskValue); for(QVector3D newPoint : this->options()->points) { typedef MaskType::DirectionType::InternalMatrixType::element_type ElemType; itk::Point< ElemType > centerPoint; centerPoint.SetElement(0, newPoint.x()); centerPoint.SetElement(1, newPoint.y()); centerPoint.SetElement(2, newPoint.z()); const QVector3D vup = this->options()->view->viewUp(); const QVector3D vpn = this->options()->view->viewPlaneNormal(); vnl_vector_fixed vecVup(vup.x(), vup.y(), vup.z() ); vnl_vector_fixed vecVpn(vpn.x(), vpn.y(), vpn.z() ); vnl_vector_fixed vecRight = vnl_cross_3d(vecVup,vecVpn); if ( vup != d->lastVup || vpn != d->lastVpn ) { const MaskType::SpacingType & spacing = this->options()->itkMask->GetSpacing(); // Rows of the direction matrix are the directions of the image i,j,k pixel directions. const MaskType::DirectionType & direction = this->options()->itkMask->GetDirection(); // project spacing onto view. vnl_matrix_fixed projMatrix; projMatrix.set_row(0, vecRight ); projMatrix.set_row(1, vecVup ); projMatrix = projMatrix * direction.GetVnlMatrix(); // (direction.GetTranspose()); double sampleSpacing[2]; // Compute the total projection of each of the spacings onto the view plane x & y. for (int i = 0; i < 2; i++) //output axis { double s = 0; // sum squares double r = 0; for (int j = 0; j < 3; j++) { const double elem = projMatrix.get(i,j); const double elem2 = elem*elem; s += elem2*(spacing[j] >= 0 ? spacing[j] : -spacing[j]); r += elem2; } s /= r; sampleSpacing[i] = s; } // Store result. std::copy( sampleSpacing, sampleSpacing + 2, d->sampleSpacing); //Oversample d->sampleSpacing[0] *= 0.5; d->sampleSpacing[1] *= 0.5; d->lastVup = vup; d->lastVpn = vpn; } const double radius2 = this->options()->radius*this->options()->radius; const int Nx = std::max( 1, (int)std::ceil(this->options()->radius/d->sampleSpacing[0]) ); const int Ny = std::max( 1, (int)std::ceil(this->options()->radius/d->sampleSpacing[1]) ); MaskType::PixelType pxValue = this->options()->maskValue; MaskType::IndexType index; itk::Point testPt; for ( int y(-Ny); y < Ny; ++y ) { double dy = y*d->sampleSpacing[1]; for ( int x(-Nx); x < Nx; ++x ) { double dx = x*d->sampleSpacing[0]; if ( dx*dx + dy*dy > radius2 ) continue; for ( int ic(0); ic<3; ++ic) { testPt[ic] = centerPoint[ic] + dx * vecRight[ic] + dy * vecVup[ic]; } bool isInside = this->options()->itkMask->TransformPhysicalPointToIndex( testPt, index ); if ( isInside ) { this->options()->itkMask->SetPixel( index, pxValue ); d->label->AddIndex(index); } } } vtkImageView2D* poImageViewTmp = ((medVtkViewBackend*)this->options()->view->backend())->view2D; unsigned int uiLayer = this->options()->view->layer((medAbstractData*) this->options()->maskAnnotationData); vtkAlgorithm * poAlgoTmp = poImageViewTmp->GetImageAlgorithmForLayer(uiLayer); poAlgoTmp->Modified(); } } void medPaintCommand::undo() { d->labelMap->RemoveLabelObject(d->label); typedef itk::LabelMapToAttributeImageFilter< LabelMapType, MaskType > MapToImageFilter; d->filter = MapToImageFilter::New(); d->filter->SetInput(d->labelMap); d->filter->Update(); this->options()->itkMask->Graft(d->filter->GetOutput()); this->options()->view->render(); } void medPaintCommand::redo() { if(!d->label) { paint(); d->labelMap->PushLabelObject(d->label); } else { d->labelMap->PushLabelObject(d->label); typedef itk::LabelMapToAttributeImageFilter< LabelMapType, MaskType > MapToImageFilter; d->filter = MapToImageFilter::New(); d->filter->SetInput(d->labelMap); d->filter->Update(); this->options()->itkMask->Graft(d->filter->GetOutput()); } this->options()->view->render(); }