void mitk::LabelSetImageVtkMapper2D::GenerateDataForRenderer(mitk::BaseRenderer *renderer)
{
  LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer);
  mitk::DataNode *node = this->GetDataNode();
  mitk::LabelSetImage *image = dynamic_cast<mitk::LabelSetImage *>(node->GetData());
  assert(image && image->IsInitialized());

  // check if there is a valid worldGeometry
  const PlaneGeometry *worldGeometry = renderer->GetCurrentWorldPlaneGeometry();
  if ((worldGeometry == NULL) || (!worldGeometry->IsValid()) || (!worldGeometry->HasReferenceGeometry()))
    return;

  image->Update();

  int numberOfLayers = image->GetNumberOfLayers();
  int activeLayer = image->GetActiveLayer();

  float opacity = 1.0f;
  node->GetOpacity(opacity, renderer, "opacity");

  if (numberOfLayers != localStorage->m_NumberOfLayers)
  {
    localStorage->m_NumberOfLayers = numberOfLayers;
    localStorage->m_ReslicedImageVector.clear();
    localStorage->m_ReslicerVector.clear();
    localStorage->m_LayerTextureVector.clear();
    localStorage->m_LevelWindowFilterVector.clear();
    localStorage->m_LayerMapperVector.clear();
    localStorage->m_LayerActorVector.clear();

    localStorage->m_Actors = vtkSmartPointer<vtkPropAssembly>::New();

    for (int lidx = 0; lidx < numberOfLayers; ++lidx)
    {
      localStorage->m_ReslicedImageVector.push_back(vtkSmartPointer<vtkImageData>::New());
      localStorage->m_ReslicerVector.push_back(mitk::ExtractSliceFilter::New());
      localStorage->m_LayerTextureVector.push_back(vtkSmartPointer<vtkNeverTranslucentTexture>::New());
      localStorage->m_LevelWindowFilterVector.push_back(vtkSmartPointer<vtkMitkLevelWindowFilter>::New());
      localStorage->m_LayerMapperVector.push_back(vtkSmartPointer<vtkPolyDataMapper>::New());
      localStorage->m_LayerActorVector.push_back(vtkSmartPointer<vtkActor>::New());

      // do not repeat the texture (the image)
      localStorage->m_LayerTextureVector[lidx]->RepeatOff();

      // set corresponding mappers for the actors
      localStorage->m_LayerActorVector[lidx]->SetMapper(localStorage->m_LayerMapperVector[lidx]);

      localStorage->m_Actors->AddPart(localStorage->m_LayerActorVector[lidx]);
    }

    localStorage->m_Actors->AddPart(localStorage->m_OutlineShadowActor);
    localStorage->m_Actors->AddPart(localStorage->m_OutlineActor);
  }

  // early out if there is no intersection of the current rendering geometry
  // and the geometry of the image that is to be rendered.
  if (!RenderingGeometryIntersectsImage(worldGeometry, image->GetSlicedGeometry()))
  {
    // set image to NULL, to clear the texture in 3D, because
    // the latest image is used there if the plane is out of the geometry
    // see bug-13275
    for (int lidx = 0; lidx < numberOfLayers; ++lidx)
    {
      localStorage->m_ReslicedImageVector[lidx] = NULL;
      localStorage->m_LayerMapperVector[lidx]->SetInputData(localStorage->m_EmptyPolyData);
      localStorage->m_OutlineActor->SetVisibility(false);
      localStorage->m_OutlineShadowActor->SetVisibility(false);
    }
    return;
  }

  for (int lidx = 0; lidx < numberOfLayers; ++lidx)
  {
    mitk::Image *layerImage = NULL;

    // set main input for ExtractSliceFilter
    if (lidx == activeLayer)
      layerImage = image;
    else
      layerImage = image->GetLayerImage(lidx);

    localStorage->m_ReslicerVector[lidx]->SetInput(layerImage);
    localStorage->m_ReslicerVector[lidx]->SetWorldGeometry(worldGeometry);
    localStorage->m_ReslicerVector[lidx]->SetTimeStep(this->GetTimestep());

    // set the transformation of the image to adapt reslice axis
    localStorage->m_ReslicerVector[lidx]->SetResliceTransformByGeometry(
      layerImage->GetTimeGeometry()->GetGeometryForTimeStep(this->GetTimestep()));

    // is the geometry of the slice based on the image image or the worldgeometry?
    bool inPlaneResampleExtentByGeometry = false;
    node->GetBoolProperty("in plane resample extent by geometry", inPlaneResampleExtentByGeometry, renderer);
    localStorage->m_ReslicerVector[lidx]->SetInPlaneResampleExtentByGeometry(inPlaneResampleExtentByGeometry);
    localStorage->m_ReslicerVector[lidx]->SetInterpolationMode(ExtractSliceFilter::RESLICE_NEAREST);
    localStorage->m_ReslicerVector[lidx]->SetVtkOutputRequest(true);

    // this is needed when thick mode was enabled before. These variables have to be reset to default values
    localStorage->m_ReslicerVector[lidx]->SetOutputDimensionality(2);
    localStorage->m_ReslicerVector[lidx]->SetOutputSpacingZDirection(1.0);
    localStorage->m_ReslicerVector[lidx]->SetOutputExtentZDirection(0, 0);

    // Bounds information for reslicing (only required if reference geometry is present)
    // this used for generating a vtkPLaneSource with the right size
    double sliceBounds[6];
    sliceBounds[0] = 0.0;
    sliceBounds[1] = 0.0;
    sliceBounds[2] = 0.0;
    sliceBounds[3] = 0.0;
    sliceBounds[4] = 0.0;
    sliceBounds[5] = 0.0;

    localStorage->m_ReslicerVector[lidx]->GetClippedPlaneBounds(sliceBounds);

    // setup the textured plane
    this->GeneratePlane(renderer, sliceBounds);

    // get the spacing of the slice
    localStorage->m_mmPerPixel = localStorage->m_ReslicerVector[lidx]->GetOutputSpacing();
    localStorage->m_ReslicerVector[lidx]->Modified();
    // start the pipeline with updating the largest possible, needed if the geometry of the image has changed
    localStorage->m_ReslicerVector[lidx]->UpdateLargestPossibleRegion();
    localStorage->m_ReslicedImageVector[lidx] = localStorage->m_ReslicerVector[lidx]->GetVtkOutput();

    const PlaneGeometry *planeGeometry = dynamic_cast<const PlaneGeometry *>(worldGeometry);

    double textureClippingBounds[6];
    for (auto &textureClippingBound : textureClippingBounds)
    {
      textureClippingBound = 0.0;
    }

    // Calculate the actual bounds of the transformed plane clipped by the
    // dataset bounding box; this is required for drawing the texture at the
    // correct position during 3D mapping.
    mitk::PlaneClipping::CalculateClippedPlaneBounds(layerImage->GetGeometry(), planeGeometry, textureClippingBounds);

    textureClippingBounds[0] = static_cast<int>(textureClippingBounds[0] / localStorage->m_mmPerPixel[0] + 0.5);
    textureClippingBounds[1] = static_cast<int>(textureClippingBounds[1] / localStorage->m_mmPerPixel[0] + 0.5);
    textureClippingBounds[2] = static_cast<int>(textureClippingBounds[2] / localStorage->m_mmPerPixel[1] + 0.5);
    textureClippingBounds[3] = static_cast<int>(textureClippingBounds[3] / localStorage->m_mmPerPixel[1] + 0.5);

    // clipping bounds for cutting the imageLayer
    localStorage->m_LevelWindowFilterVector[lidx]->SetClippingBounds(textureClippingBounds);

    localStorage->m_LevelWindowFilterVector[lidx]->SetLookupTable(
      image->GetLabelSet(lidx)->GetLookupTable()->GetVtkLookupTable());

    // do not use a VTK lookup table (we do that ourselves in m_LevelWindowFilter)
    localStorage->m_LayerTextureVector[lidx]->MapColorScalarsThroughLookupTableOff();

    // connect the imageLayer with the levelwindow filter
    localStorage->m_LevelWindowFilterVector[lidx]->SetInputData(localStorage->m_ReslicedImageVector[lidx]);
    // connect the texture with the output of the levelwindow filter

    // check for texture interpolation property
    bool textureInterpolation = false;
    node->GetBoolProperty("texture interpolation", textureInterpolation, renderer);

    // set the interpolation modus according to the property
    localStorage->m_LayerTextureVector[lidx]->SetInterpolate(textureInterpolation);

    localStorage->m_LayerTextureVector[lidx]->SetInputConnection(
      localStorage->m_LevelWindowFilterVector[lidx]->GetOutputPort());

    this->TransformActor(renderer);

    // set the plane as input for the mapper
    localStorage->m_LayerMapperVector[lidx]->SetInputConnection(localStorage->m_Plane->GetOutputPort());

    // set the texture for the actor
    localStorage->m_LayerActorVector[lidx]->SetTexture(localStorage->m_LayerTextureVector[lidx]);
    localStorage->m_LayerActorVector[lidx]->GetProperty()->SetOpacity(opacity);
  }

  mitk::Label* activeLabel = image->GetActiveLabel(activeLayer);
  if (nullptr != activeLabel)
  {
    bool contourActive = false;
    node->GetBoolProperty("labelset.contour.active", contourActive, renderer);
    if (contourActive && activeLabel->GetVisible()) //contour rendering
    {
      //generate contours/outlines
      localStorage->m_OutlinePolyData =
        this->CreateOutlinePolyData(renderer, localStorage->m_ReslicedImageVector[activeLayer], activeLabel->GetValue());
      localStorage->m_OutlineActor->SetVisibility(true);
      localStorage->m_OutlineShadowActor->SetVisibility(true);
      const mitk::Color& color = activeLabel->GetColor();
      localStorage->m_OutlineActor->GetProperty()->SetColor(color.GetRed(), color.GetGreen(), color.GetBlue());
      localStorage->m_OutlineShadowActor->GetProperty()->SetColor(0, 0, 0);

      float contourWidth(2.0);
      node->GetFloatProperty("labelset.contour.width", contourWidth, renderer);
      localStorage->m_OutlineActor->GetProperty()->SetLineWidth(contourWidth);
      localStorage->m_OutlineShadowActor->GetProperty()->SetLineWidth(contourWidth * 1.5);

      localStorage->m_OutlineActor->GetProperty()->SetOpacity(opacity);
      localStorage->m_OutlineShadowActor->GetProperty()->SetOpacity(opacity);

      localStorage->m_OutlineMapper->SetInputData(localStorage->m_OutlinePolyData);
      return;
    }
  }
  localStorage->m_OutlineActor->SetVisibility(false);
  localStorage->m_OutlineShadowActor->SetVisibility(false);
}
Esempio n. 2
0
void mitk::ImageVtkMapper2D::GenerateDataForRenderer( mitk::BaseRenderer *renderer )
{
  LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer);

  mitk::Image *input = const_cast< mitk::Image * >( this->GetInput() );
  mitk::DataNode* datanode = this->GetDataNode();

  if ( input == NULL || input->IsInitialized() == false )
  {
    return;
  }

  //check if there is a valid worldGeometry
  const PlaneGeometry *worldGeometry = renderer->GetCurrentWorldPlaneGeometry();
  if( ( worldGeometry == NULL ) || ( !worldGeometry->IsValid() ) || ( !worldGeometry->HasReferenceGeometry() ))
  {
    return;
  }

  input->Update();

  // early out if there is no intersection of the current rendering geometry
  // and the geometry of the image that is to be rendered.
  if ( !RenderingGeometryIntersectsImage( worldGeometry, input->GetSlicedGeometry() ) )
  {
    // set image to NULL, to clear the texture in 3D, because
    // the latest image is used there if the plane is out of the geometry
    // see bug-13275
    localStorage->m_ReslicedImage = NULL;
    localStorage->m_Mapper->SetInputData( localStorage->m_EmptyPolyData );
    return;
  }


  //set main input for ExtractSliceFilter
  localStorage->m_Reslicer->SetInput(input);
  localStorage->m_Reslicer->SetWorldGeometry(worldGeometry);
  localStorage->m_Reslicer->SetTimeStep( this->GetTimestep() );


  //set the transformation of the image to adapt reslice axis
  localStorage->m_Reslicer->SetResliceTransformByGeometry( input->GetTimeGeometry()->GetGeometryForTimeStep( this->GetTimestep() ) );


  //is the geometry of the slice based on the input image or the worldgeometry?
  bool inPlaneResampleExtentByGeometry = false;
  datanode->GetBoolProperty("in plane resample extent by geometry", inPlaneResampleExtentByGeometry, renderer);
  localStorage->m_Reslicer->SetInPlaneResampleExtentByGeometry(inPlaneResampleExtentByGeometry);


  // Initialize the interpolation mode for resampling; switch to nearest
  // neighbor if the input image is too small.
  if ( (input->GetDimension() >= 3) && (input->GetDimension(2) > 1) )
  {
    VtkResliceInterpolationProperty *resliceInterpolationProperty;
    datanode->GetProperty(
          resliceInterpolationProperty, "reslice interpolation" );

    int interpolationMode = VTK_RESLICE_NEAREST;
    if ( resliceInterpolationProperty != NULL )
    {
      interpolationMode = resliceInterpolationProperty->GetInterpolation();
    }

    switch ( interpolationMode )
    {
    case VTK_RESLICE_NEAREST:
      localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_NEAREST);
      break;
    case VTK_RESLICE_LINEAR:
      localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_LINEAR);
      break;
    case VTK_RESLICE_CUBIC:
      localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_CUBIC);
      break;
    }
  }
  else
  {
    localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_NEAREST);
  }

  //set the vtk output property to true, makes sure that no unneeded mitk image convertion
  //is done.
  localStorage->m_Reslicer->SetVtkOutputRequest(true);


  //Thickslicing
  int thickSlicesMode = 0;
  int thickSlicesNum = 1;
  // Thick slices parameters
  if( input->GetPixelType().GetNumberOfComponents() == 1 ) // for now only single component are allowed
  {
    DataNode *dn=renderer->GetCurrentWorldPlaneGeometryNode();
    if(dn)
    {
      ResliceMethodProperty *resliceMethodEnumProperty=0;

      if( dn->GetProperty( resliceMethodEnumProperty, "reslice.thickslices" ) && resliceMethodEnumProperty )
        thickSlicesMode = resliceMethodEnumProperty->GetValueAsId();

      IntProperty *intProperty=0;
      if( dn->GetProperty( intProperty, "reslice.thickslices.num" ) && intProperty )
      {
        thickSlicesNum = intProperty->GetValue();
        if(thickSlicesNum < 1) thickSlicesNum=1;
        if(thickSlicesNum > 10) thickSlicesNum=10;
      }
    }
    else
    {
      MITK_WARN << "no associated widget plane data tree node found";
    }
  }

  const PlaneGeometry *planeGeometry = dynamic_cast< const PlaneGeometry * >( worldGeometry );

  if(thickSlicesMode > 0)
  {
    double dataZSpacing = 1.0;

    Vector3D normInIndex, normal;

    if ( planeGeometry != NULL ){
      normal = planeGeometry->GetNormal();
    }else{
      const mitk::AbstractTransformGeometry* abstractGeometry = dynamic_cast< const AbstractTransformGeometry * >(worldGeometry);
      if(abstractGeometry != NULL)
        normal = abstractGeometry->GetPlane()->GetNormal();
      else
        return; //no fitting geometry set
    }
    normal.Normalize();

    input->GetTimeGeometry()->GetGeometryForTimeStep( this->GetTimestep() )->WorldToIndex( normal, normInIndex );

    dataZSpacing = 1.0 / normInIndex.GetNorm();

    localStorage->m_Reslicer->SetOutputDimensionality( 3 );
    localStorage->m_Reslicer->SetOutputSpacingZDirection(dataZSpacing);
    localStorage->m_Reslicer->SetOutputExtentZDirection( -thickSlicesNum, 0+thickSlicesNum );

    // Do the reslicing. Modified() is called to make sure that the reslicer is
    // executed even though the input geometry information did not change; this
    // is necessary when the input /em data, but not the /em geometry changes.
    localStorage->m_TSFilter->SetThickSliceMode( thickSlicesMode-1 );
    localStorage->m_TSFilter->SetInputData( localStorage->m_Reslicer->GetVtkOutput() );

    //vtkFilter=>mitkFilter=>vtkFilter update mechanism will fail without calling manually
    localStorage->m_Reslicer->Modified();
    localStorage->m_Reslicer->Update();

    localStorage->m_TSFilter->Modified();
    localStorage->m_TSFilter->Update();
    localStorage->m_ReslicedImage = localStorage->m_TSFilter->GetOutput();
  }
  else
  {
    //this is needed when thick mode was enable bevore. These variable have to be reset to default values
    localStorage->m_Reslicer->SetOutputDimensionality( 2 );
    localStorage->m_Reslicer->SetOutputSpacingZDirection(1.0);
    localStorage->m_Reslicer->SetOutputExtentZDirection( 0, 0 );


    localStorage->m_Reslicer->Modified();
    //start the pipeline with updating the largest possible, needed if the geometry of the input has changed
    localStorage->m_Reslicer->UpdateLargestPossibleRegion();
    localStorage->m_ReslicedImage = localStorage->m_Reslicer->GetVtkOutput();
  }

  // Bounds information for reslicing (only reuqired if reference geometry
  // is present)
  //this used for generating a vtkPLaneSource with the right size
  double sliceBounds[6];
  for ( int i = 0; i < 6; ++i )
  {
    sliceBounds[i] = 0.0;
  }
  localStorage->m_Reslicer->GetClippedPlaneBounds(sliceBounds);

  //get the spacing of the slice
  localStorage->m_mmPerPixel = localStorage->m_Reslicer->GetOutputSpacing();

  // calculate minimum bounding rect of IMAGE in texture
  {
    double textureClippingBounds[6];
    for ( int i = 0; i < 6; ++i )
    {
      textureClippingBounds[i] = 0.0;
    }
    // Calculate the actual bounds of the transformed plane clipped by the
    // dataset bounding box; this is required for drawing the texture at the
    // correct position during 3D mapping.
    mitk::PlaneClipping::CalculateClippedPlaneBounds( input->GetGeometry(), planeGeometry, textureClippingBounds );

    textureClippingBounds[0] = static_cast< int >( textureClippingBounds[0] / localStorage->m_mmPerPixel[0] + 0.5 );
    textureClippingBounds[1] = static_cast< int >( textureClippingBounds[1] / localStorage->m_mmPerPixel[0] + 0.5 );
    textureClippingBounds[2] = static_cast< int >( textureClippingBounds[2] / localStorage->m_mmPerPixel[1] + 0.5 );
    textureClippingBounds[3] = static_cast< int >( textureClippingBounds[3] / localStorage->m_mmPerPixel[1] + 0.5 );

    //clipping bounds for cutting the image
    localStorage->m_LevelWindowFilter->SetClippingBounds(textureClippingBounds);
  }

  //get the number of scalar components to distinguish between different image types
  int numberOfComponents = localStorage->m_ReslicedImage->GetNumberOfScalarComponents();
  //get the binary property
  bool binary = false;
  bool binaryOutline = false;
  datanode->GetBoolProperty( "binary", binary, renderer );
  if(binary) //binary image
  {
    datanode->GetBoolProperty( "outline binary", binaryOutline, renderer );
    if(binaryOutline) //contour rendering
    {
      if ( input->GetPixelType().GetBpe() <= 8 )
      {
        //generate contours/outlines
        localStorage->m_OutlinePolyData = CreateOutlinePolyData(renderer);

        float binaryOutlineWidth(1.0);
        if ( datanode->GetFloatProperty( "outline width", binaryOutlineWidth, renderer ) )
        {
          if ( localStorage->m_Actors->GetNumberOfPaths() > 1 )
          {
            float binaryOutlineShadowWidth(1.5);
            datanode->GetFloatProperty( "outline shadow width", binaryOutlineShadowWidth, renderer );

            dynamic_cast<vtkActor*>(localStorage->m_Actors->GetParts()->GetItemAsObject(0))
                ->GetProperty()->SetLineWidth( binaryOutlineWidth * binaryOutlineShadowWidth );
          }

          localStorage->m_Actor->GetProperty()->SetLineWidth( binaryOutlineWidth );
        }
      }
      else
      {
        binaryOutline = false;
        this->ApplyLookuptable(renderer);
        MITK_WARN << "Type of all binary images should be (un)signed char. Outline does not work on other pixel types!";
      }
    }
    else //standard binary image
    {
      if(numberOfComponents != 1)
      {
        MITK_ERROR << "Rendering Error: Binary Images with more then 1 component are not supported!";
      }
    }
  }

  this->ApplyOpacity( renderer );
  this->ApplyRenderingMode(renderer);

  // do not use a VTK lookup table (we do that ourselves in m_LevelWindowFilter)
  localStorage->m_Texture->MapColorScalarsThroughLookupTableOff();

  int displayedComponent = 0;

  if (datanode->GetIntProperty("Image.Displayed Component", displayedComponent, renderer) && numberOfComponents > 1)
  {
    localStorage->m_VectorComponentExtractor->SetComponents(displayedComponent);
    localStorage->m_VectorComponentExtractor->SetInputData(localStorage->m_ReslicedImage);

    localStorage->m_LevelWindowFilter->SetInputConnection(localStorage->m_VectorComponentExtractor->GetOutputPort(0));
  }
  else
  {
    //connect the input with the levelwindow filter
    localStorage->m_LevelWindowFilter->SetInputData(localStorage->m_ReslicedImage);
  }

  // check for texture interpolation property
  bool textureInterpolation = false;
  GetDataNode()->GetBoolProperty( "texture interpolation", textureInterpolation, renderer );

  //set the interpolation modus according to the property
  localStorage->m_Texture->SetInterpolate(textureInterpolation);

  // connect the texture with the output of the levelwindow filter
  localStorage->m_Texture->SetInputConnection(localStorage->m_LevelWindowFilter->GetOutputPort());

  this->TransformActor( renderer );

  vtkActor* contourShadowActor = dynamic_cast<vtkActor*> (localStorage->m_Actors->GetParts()->GetItemAsObject(0));

  if(binary && binaryOutline) //connect the mapper with the polyData which contains the lines
  {
    //We need the contour for the binary outline property as actor
    localStorage->m_Mapper->SetInputData(localStorage->m_OutlinePolyData);
    localStorage->m_Actor->SetTexture(NULL); //no texture for contours

    bool binaryOutlineShadow( false );
    datanode->GetBoolProperty( "outline binary shadow", binaryOutlineShadow, renderer );

    if ( binaryOutlineShadow )
      contourShadowActor->SetVisibility( true );
    else
      contourShadowActor->SetVisibility( false );
  }
  else
  { //Connect the mapper with the input texture. This is the standard case.
    //setup the textured plane
    this->GeneratePlane( renderer, sliceBounds );
    //set the plane as input for the mapper
    localStorage->m_Mapper->SetInputConnection(localStorage->m_Plane->GetOutputPort());
    //set the texture for the actor

    localStorage->m_Actor->SetTexture(localStorage->m_Texture);
    contourShadowActor->SetVisibility( false );
  }

  // We have been modified => save this for next Update()
  localStorage->m_LastUpdateTime.Modified();
}