void
  mitk::SlicedGeometry3D::ExecuteOperation(Operation* operation)
{
  switch ( operation->GetOperationType() )
  {
  case OpNOTHING:
    break;

  case OpROTATE:
    if ( m_EvenlySpaced )
    {
      // Need a reference frame to align the rotation
      if ( m_ReferenceGeometry )
      {
        // Clear all generated geometries and then rotate only the first slice.
        // The other slices will be re-generated on demand

        // Save first slice
        PlaneGeometry::Pointer geometry2D = m_PlaneGeometries[0];

        RotationOperation *rotOp = dynamic_cast< RotationOperation * >( operation );

        // Generate a RotationOperation using the dataset center instead of
        // the supplied rotation center. This is necessary so that the rotated
        // zero-plane does not shift away. The supplied center is instead used
        // to adjust the slice stack afterwards.
        Point3D center = m_ReferenceGeometry->GetCenter();

        RotationOperation centeredRotation(
          rotOp->GetOperationType(),
          center,
          rotOp->GetVectorOfRotation(),
          rotOp->GetAngleOfRotation()
          );

        // Rotate first slice
        geometry2D->ExecuteOperation( &centeredRotation );

        // Clear the slice stack and adjust it according to the center of
        // the dataset and the supplied rotation center (see documentation of
        // ReinitializePlanes)
        this->ReinitializePlanes( center, rotOp->GetCenterOfRotation() );

        geometry2D->SetSpacing(this->GetSpacing());

        if ( m_SliceNavigationController )
        {
          m_SliceNavigationController->SelectSliceByPoint(
            rotOp->GetCenterOfRotation() );
          m_SliceNavigationController->AdjustSliceStepperRange();
        }

        BaseGeometry::ExecuteOperation( &centeredRotation );
      }
      else
      {
        // we also have to consider the case, that there is no reference geometry available.
        if ( m_PlaneGeometries.size() > 0 )
        {
          // Reach through to all slices in my container
          for (auto iter = m_PlaneGeometries.begin();
            iter != m_PlaneGeometries.end();
            ++iter)
          {
            // Test for empty slices, which can happen if evenly spaced geometry
            if ((*iter).IsNotNull())
            {
              (*iter)->ExecuteOperation(operation);
            }
          }

          // rotate overall geometry
          RotationOperation *rotOp = dynamic_cast< RotationOperation * >( operation );
          BaseGeometry::ExecuteOperation( rotOp);
        }
      }
    }
    else
    {
      // Reach through to all slices
      for (auto iter = m_PlaneGeometries.begin();
        iter != m_PlaneGeometries.end();
        ++iter)
      {
        (*iter)->ExecuteOperation(operation);
      }
    }
    break;

  case OpORIENT:
    if ( m_EvenlySpaced )
    {
      // get operation data
      PlaneOperation *planeOp = dynamic_cast< PlaneOperation * >( operation );

      // Get first slice
      PlaneGeometry::Pointer planeGeometry = m_PlaneGeometries[0];

      // Need a PlaneGeometry, a PlaneOperation and a reference frame to
      // carry out the re-orientation. If not all avaialble, stop here
      if ( !m_ReferenceGeometry                                                                       ||
           ( !planeGeometry || dynamic_cast<AbstractTransformGeometry*>(planeGeometry.GetPointer()) ) ||
           !planeOp )
      {
        break;
      }

      // General Behavior:
      // Clear all generated geometries and then rotate only the first slice.
      // The other slices will be re-generated on demand

      //
      // 1st Step: Reorient Normal Vector of first plane
      //
      Point3D center = planeOp->GetPoint(); //m_ReferenceGeometry->GetCenter();
      mitk::Vector3D currentNormal = planeGeometry->GetNormal();
      mitk::Vector3D newNormal;
      if (planeOp->AreAxisDefined())
      {
        // If planeOp was defined by one centerpoint and two axis vectors
        newNormal = CrossProduct(planeOp->GetAxisVec0(), planeOp->GetAxisVec1());
      }
      else
      {
        // If planeOp was defined by one centerpoint and one normal vector
        newNormal = planeOp->GetNormal();
      }

      // Get Rotation axis und angle
      currentNormal.Normalize();
      newNormal.Normalize();
      ScalarType rotationAngle = angle(currentNormal.GetVnlVector(),newNormal.GetVnlVector());

      rotationAngle *= 180.0 / vnl_math::pi; // from rad to deg
      Vector3D rotationAxis = itk::CrossProduct( currentNormal, newNormal );
      if (std::abs(rotationAngle-180) < mitk::eps )
      {
        // current Normal and desired normal are not linear independent!!(e.g 1,0,0 and -1,0,0).
        // Rotation Axis should be ANY vector that is 90� to current Normal
        mitk::Vector3D helpNormal;
        helpNormal = currentNormal;
        helpNormal[0] += 1;
        helpNormal[1] -= 1;
        helpNormal[2] += 1;
        helpNormal.Normalize();
        rotationAxis = itk::CrossProduct( helpNormal, currentNormal );
      }

      RotationOperation centeredRotation(
        mitk::OpROTATE,
        center,
        rotationAxis,
        rotationAngle
        );

      // Rotate first slice
      planeGeometry->ExecuteOperation( &centeredRotation );

      // Reinitialize planes and select slice, if my rotations are all done.
      if (!planeOp->AreAxisDefined())
      {
        // Clear the slice stack and adjust it according to the center of
        // rotation and plane position (see documentation of ReinitializePlanes)
        this->ReinitializePlanes( center, planeOp->GetPoint() );

        if ( m_SliceNavigationController )
        {
          m_SliceNavigationController->SelectSliceByPoint( planeOp->GetPoint() );
          m_SliceNavigationController->AdjustSliceStepperRange();
        }
      }

      // Also apply rotation on the slicedGeometry - Geometry3D (Bounding geometry)
      BaseGeometry::ExecuteOperation( &centeredRotation );

      //
      // 2nd step. If axis vectors were defined, rotate the plane around its normal to fit these
      //

      if (planeOp->AreAxisDefined())
      {
        mitk::Vector3D vecAxixNew = planeOp->GetAxisVec0();
        vecAxixNew.Normalize();
        mitk::Vector3D VecAxisCurr = planeGeometry->GetAxisVector(0);
        VecAxisCurr.Normalize();

        ScalarType rotationAngle = angle(VecAxisCurr.GetVnlVector(),vecAxixNew.GetVnlVector());
        rotationAngle = rotationAngle * 180 / PI; // Rad to Deg

        // we rotate around the normal of the plane, but we do not know, if we need to rotate clockwise
        // or anti-clockwise. So we rotate around the crossproduct of old and new Axisvector.
        // Since both axis vectors lie in the plane, the crossproduct is the planes normal or the negative planes normal

        rotationAxis = itk::CrossProduct( VecAxisCurr, vecAxixNew  );
        if (std::abs(rotationAngle-180) < mitk::eps )
        {
          // current axisVec and desired axisVec are not linear independent!!(e.g 1,0,0 and -1,0,0).
          // Rotation Axis can be just plane Normal. (have to rotate by 180�)
          rotationAxis = newNormal;
        }

        // Perfom Rotation
        mitk::RotationOperation op(mitk::OpROTATE, center, rotationAxis, rotationAngle);
        planeGeometry->ExecuteOperation( &op );

        // Apply changes on first slice to whole slice stack
        this->ReinitializePlanes( center, planeOp->GetPoint() );

        if ( m_SliceNavigationController )
        {
          m_SliceNavigationController->SelectSliceByPoint( planeOp->GetPoint() );
          m_SliceNavigationController->AdjustSliceStepperRange();
        }

        // Also apply rotation on the slicedGeometry - Geometry3D (Bounding geometry)
        BaseGeometry::ExecuteOperation( &op );
      }
    }
    else
    {
      // Reach through to all slices
      for (auto iter = m_PlaneGeometries.begin();
        iter != m_PlaneGeometries.end();
        ++iter)
      {
        (*iter)->ExecuteOperation(operation);
      }
    }
    break;

  case OpRESTOREPLANEPOSITION:
    if ( m_EvenlySpaced )
    {
      // Save first slice
      PlaneGeometry::Pointer planeGeometry = m_PlaneGeometries[0];

      RestorePlanePositionOperation *restorePlaneOp = dynamic_cast< RestorePlanePositionOperation* >( operation );

      // Need a PlaneGeometry, a PlaneOperation and a reference frame to
      // carry out the re-orientation
      if ( m_ReferenceGeometry && (planeGeometry && dynamic_cast<AbstractTransformGeometry*>(planeGeometry.GetPointer()) == nullptr) && restorePlaneOp )
      {
        // Clear all generated geometries and then rotate only the first slice.
        // The other slices will be re-generated on demand

        // Rotate first slice
        planeGeometry->ExecuteOperation( restorePlaneOp );

        m_DirectionVector = restorePlaneOp->GetDirectionVector();

        double centerOfRotationDistance =
          planeGeometry->SignedDistanceFromPlane( m_ReferenceGeometry->GetCenter() );

        if ( centerOfRotationDistance > 0 )
        {
          m_DirectionVector = m_DirectionVector;
        }
        else
        {
          m_DirectionVector = -m_DirectionVector;
        }

        Vector3D spacing = restorePlaneOp->GetSpacing();

        Superclass::SetSpacing( spacing );

        // /*Now we need to calculate the number of slices in the plane's normal
        // direction, so that the entire volume is covered. This is done by first
        // calculating the dot product between the volume diagonal (the maximum
        // distance inside the volume) and the normal, and dividing this value by
        // the directed spacing calculated above.*/
        ScalarType directedExtent =
          std::abs( m_ReferenceGeometry->GetExtentInMM( 0 ) * m_DirectionVector[0] )
          + std::abs( m_ReferenceGeometry->GetExtentInMM( 1 ) * m_DirectionVector[1] )
          + std::abs( m_ReferenceGeometry->GetExtentInMM( 2 ) * m_DirectionVector[2] );

        if ( directedExtent >= spacing[2] )
        {
          m_Slices = static_cast< unsigned int >(directedExtent / spacing[2] + 0.5);
        }
        else
        {
          m_Slices = 1;
        }

        m_PlaneGeometries.assign( m_Slices, PlaneGeometry::Pointer( nullptr ) );

        if ( m_Slices > 0 )
        {
          m_PlaneGeometries[0] = planeGeometry;
        }

        m_SliceNavigationController->GetSlice()->SetSteps( m_Slices );

        this->Modified();

        //End Reinitialization

        if ( m_SliceNavigationController )
        {
          m_SliceNavigationController->GetSlice()->SetPos( restorePlaneOp->GetPos() );
          m_SliceNavigationController->AdjustSliceStepperRange();
        }
        BaseGeometry::ExecuteOperation(restorePlaneOp);
      }
    }
    else
    {
      // Reach through to all slices
      for (auto iter = m_PlaneGeometries.begin();
        iter != m_PlaneGeometries.end();
        ++iter)
      {
        (*iter)->ExecuteOperation(operation);
      }
    }
    break;

  case OpAPPLYTRANSFORMMATRIX:

    // Clear all generated geometries and then transform only the first slice.
    // The other slices will be re-generated on demand

    // Save first slice
    PlaneGeometry::Pointer geometry2D = m_PlaneGeometries[0];

    ApplyTransformMatrixOperation *applyMatrixOp = dynamic_cast< ApplyTransformMatrixOperation* >( operation );

    // Apply transformation to first plane
    geometry2D->ExecuteOperation( applyMatrixOp );

    // Generate a ApplyTransformMatrixOperation using the dataset center instead of
    // the supplied rotation center. The supplied center is instead used to adjust the
    // slice stack afterwards (see OpROTATE).
    Point3D center = m_ReferenceGeometry->GetCenter();

    // Clear the slice stack and adjust it according to the center of
    // the dataset and the supplied rotation center (see documentation of
    // ReinitializePlanes)
    this->ReinitializePlanes( center, applyMatrixOp->GetReferencePoint() );

    BaseGeometry::ExecuteOperation( applyMatrixOp );
    break;
  }

  this->Modified();
}
Beispiel #2
0
void mitk::BaseGeometry::ExecuteOperation(Operation *operation)
{
  mitk::ModifiedLock lock(this);

  vtkTransform *vtktransform = vtkTransform::New();
  vtktransform->SetMatrix(this->GetVtkMatrix());
  switch (operation->GetOperationType())
  {
    case OpNOTHING:
      break;
    case OpMOVE:
    {
      mitk::PointOperation *pointOp = dynamic_cast<mitk::PointOperation *>(operation);
      if (pointOp == nullptr)
      {
        MITK_ERROR << "Point move operation is null!";
        return;
      }
      mitk::Point3D newPos = pointOp->GetPoint();
      ScalarType data[3];
      vtktransform->GetPosition(data);
      vtktransform->PostMultiply();
      vtktransform->Translate(newPos[0], newPos[1], newPos[2]);
      vtktransform->PreMultiply();
      break;
    }
    case OpSCALE:
    {
      mitk::ScaleOperation *scaleOp = dynamic_cast<mitk::ScaleOperation *>(operation);
      if (scaleOp == nullptr)
      {
        MITK_ERROR << "Scale operation is null!";
        return;
      }
      mitk::Point3D newScale = scaleOp->GetScaleFactor();
      ScalarType scalefactor[3];

      scalefactor[0] = 1 + (newScale[0] / GetMatrixColumn(0).magnitude());
      scalefactor[1] = 1 + (newScale[1] / GetMatrixColumn(1).magnitude());
      scalefactor[2] = 1 + (newScale[2] / GetMatrixColumn(2).magnitude());

      mitk::Point3D anchor = scaleOp->GetScaleAnchorPoint();

      vtktransform->PostMultiply();
      vtktransform->Translate(-anchor[0], -anchor[1], -anchor[2]);
      vtktransform->Scale(scalefactor[0], scalefactor[1], scalefactor[2]);
      vtktransform->Translate(anchor[0], anchor[1], anchor[2]);
      break;
    }
    case OpROTATE:
    {
      mitk::RotationOperation *rotateOp = dynamic_cast<mitk::RotationOperation *>(operation);
      if (rotateOp == nullptr)
      {
        MITK_ERROR << "Rotation operation is null!";
        return;
      }
      Vector3D rotationVector = rotateOp->GetVectorOfRotation();
      Point3D center = rotateOp->GetCenterOfRotation();
      ScalarType angle = rotateOp->GetAngleOfRotation();
      vtktransform->PostMultiply();
      vtktransform->Translate(-center[0], -center[1], -center[2]);
      vtktransform->RotateWXYZ(angle, rotationVector[0], rotationVector[1], rotationVector[2]);
      vtktransform->Translate(center[0], center[1], center[2]);
      vtktransform->PreMultiply();
      break;
    }
    case OpRESTOREPLANEPOSITION:
    {
      // Copy necessary to avoid vtk warning
      vtkMatrix4x4 *matrix = vtkMatrix4x4::New();
      TransferItkTransformToVtkMatrix(
        dynamic_cast<mitk::RestorePlanePositionOperation *>(operation)->GetTransform().GetPointer(), matrix);
      vtktransform->SetMatrix(matrix);
      matrix->Delete();
      break;
    }
    case OpAPPLYTRANSFORMMATRIX:
    {
      ApplyTransformMatrixOperation *applyMatrixOp = dynamic_cast<ApplyTransformMatrixOperation *>(operation);
      vtktransform->SetMatrix(applyMatrixOp->GetMatrix());
      break;
    }
    default:
      vtktransform->Delete();
      return;
  }
  this->SetVtkMatrixDeepCopy(vtktransform);
  Modified();
  vtktransform->Delete();
}
Beispiel #3
0
void mitk::BaseGeometry::ExecuteOperation(Operation* operation)
{
  mitk::ModifiedLock lock(this);

  vtkTransform *vtktransform = vtkTransform::New();
  vtktransform->SetMatrix(m_VtkMatrix);
  switch (operation->GetOperationType())
  {
  case OpNOTHING:
    break;
  case OpMOVE:
    {
      mitk::PointOperation *pointOp = dynamic_cast<mitk::PointOperation *>(operation);
      if (pointOp == NULL)
      {
        //mitk::StatusBar::GetInstance()->DisplayText("received wrong type of operation!See mitkAffineInteractor.cpp", 10000);
        return;
      }
      mitk::Point3D newPos = pointOp->GetPoint();
      ScalarType data[3];
      vtktransform->GetPosition(data);
      vtktransform->PostMultiply();
      vtktransform->Translate(newPos[0], newPos[1], newPos[2]);
      vtktransform->PreMultiply();
      break;
    }
  case OpSCALE:
    {
      mitk::PointOperation *pointOp = dynamic_cast<mitk::PointOperation *>(operation);
      if (pointOp == NULL)
      {
        //mitk::StatusBar::GetInstance()->DisplayText("received wrong type of operation!See mitkAffineInteractor.cpp", 10000);
        return;
      }
      mitk::Point3D newScale = pointOp->GetPoint();
      ScalarType data[3];
      /* calculate new scale: newscale = oldscale * (oldscale + scaletoadd)/oldscale */
      data[0] = 1 + (newScale[0] / GetMatrixColumn(0).magnitude());
      data[1] = 1 + (newScale[1] / GetMatrixColumn(1).magnitude());
      data[2] = 1 + (newScale[2] / GetMatrixColumn(2).magnitude());

      mitk::Point3D center = const_cast<mitk::BoundingBox*>(m_BoundingBox.GetPointer())->GetCenter();
      ScalarType pos[3];
      vtktransform->GetPosition(pos);
      vtktransform->PostMultiply();
      vtktransform->Translate(-pos[0], -pos[1], -pos[2]);
      vtktransform->Translate(-center[0], -center[1], -center[2]);
      vtktransform->PreMultiply();
      vtktransform->Scale(data[0], data[1], data[2]);
      vtktransform->PostMultiply();
      vtktransform->Translate(+center[0], +center[1], +center[2]);
      vtktransform->Translate(pos[0], pos[1], pos[2]);
      vtktransform->PreMultiply();
      break;
    }
  case OpROTATE:
    {
      mitk::RotationOperation *rotateOp = dynamic_cast<mitk::RotationOperation *>(operation);
      if (rotateOp == NULL)
      {
        //mitk::StatusBar::GetInstance()->DisplayText("received wrong type of operation!See mitkAffineInteractor.cpp", 10000);
        return;
      }
      Vector3D rotationVector = rotateOp->GetVectorOfRotation();
      Point3D center = rotateOp->GetCenterOfRotation();
      ScalarType angle = rotateOp->GetAngleOfRotation();
      vtktransform->PostMultiply();
      vtktransform->Translate(-center[0], -center[1], -center[2]);
      vtktransform->RotateWXYZ(angle, rotationVector[0], rotationVector[1], rotationVector[2]);
      vtktransform->Translate(center[0], center[1], center[2]);
      vtktransform->PreMultiply();
      break;
    }
  case OpRESTOREPLANEPOSITION:
    {
      //Copy necessary to avoid vtk warning
      vtkMatrix4x4* matrix = vtkMatrix4x4::New();
      TransferItkTransformToVtkMatrix(dynamic_cast<mitk::RestorePlanePositionOperation*>(operation)->GetTransform().GetPointer(), matrix);
      vtktransform->SetMatrix(matrix);
      matrix->Delete();
      break;
    }
  case OpAPPLYTRANSFORMMATRIX:
    {
      ApplyTransformMatrixOperation *applyMatrixOp = dynamic_cast< ApplyTransformMatrixOperation* >( operation );
      vtktransform->SetMatrix(applyMatrixOp->GetMatrix());
      break;
    }
  default:
    vtktransform->Delete();
    return;
  }
  m_VtkMatrix->DeepCopy(vtktransform->GetMatrix());
  TransferVtkToItkTransform();
  Modified();
  vtktransform->Delete();
}