void mitk::RegionGrowingTool::OnMouseReleased(StateMachineAction*, InteractionEvent* interactionEvent)
{
    // Until OnMousePressedInside() implements a behaviour, we're just returning here whenever m_PaintingPixelValue is 0, i.e. when the user clicked inside the segmentation
    if (m_PaintingPixelValue == 0)
    {
        return;
    }

    mitk::InteractionPositionEvent* positionEvent = dynamic_cast<mitk::InteractionPositionEvent*>(interactionEvent);

    if (m_WorkingSlice.IsNotNull() && m_FillFeedbackContour && positionEvent)
    {
        // Project contour into working slice
        ContourModel* feedbackContour(FeedbackContourTool::GetFeedbackContour());
        ContourModel::Pointer projectedContour = FeedbackContourTool::ProjectContourTo2DSlice(m_WorkingSlice, feedbackContour, false, false);

        // If there is a projected contour, fill it
        if (projectedContour.IsNotNull())
        {
            MITK_DEBUG << "Filling Segmentation";
            FeedbackContourTool::FillContourInSlice(projectedContour, positionEvent->GetSender()->GetTimeStep(), m_WorkingSlice, m_PaintingPixelValue);
            this->WriteBackSegmentationResult(positionEvent, m_WorkingSlice);
            FeedbackContourTool::SetFeedbackContourVisible(false);
        }
    }
}
void mitk::RegionGrowingTool::OnMouseMoved(StateMachineAction*, InteractionEvent* interactionEvent )
{
    // Until OnMousePressedInside() implements a behaviour, we're just returning here whenever m_PaintingPixelValue is 0, i.e. when the user clicked inside the segmentation
    if (m_PaintingPixelValue == 0)
    {
        return;
    }

    mitk::InteractionPositionEvent* positionEvent = dynamic_cast<mitk::InteractionPositionEvent*>(interactionEvent);

    if ( m_ReferenceSlice.IsNotNull() && positionEvent)
    {
        // Get geometry and indices
        mitk::BaseGeometry::Pointer workingSliceGeometry;
        workingSliceGeometry = m_WorkingSlice->GetTimeGeometry()->GetGeometryForTimeStep(m_LastEventSender->GetTimeStep());
        itk::Index<2> indexInWorkingSlice2D;
        indexInWorkingSlice2D[0] = m_SeedPoint[0];
        indexInWorkingSlice2D[1] = m_SeedPoint[1];

        m_ScreenYDifference += positionEvent->GetPointerPositionOnScreen()[1] - m_LastScreenPosition[1];
        m_ScreenXDifference += positionEvent->GetPointerPositionOnScreen()[0] - m_LastScreenPosition[0];
        m_LastScreenPosition = positionEvent->GetPointerPositionOnScreen();

        // Moving the mouse up and down adjusts the width of the threshold window, moving it left and right shifts the threshold window
        m_Thresholds[0] = std::min<ScalarType>(m_SeedValue, m_InitialThresholds[0] - (m_ScreenYDifference - m_ScreenXDifference) * m_MouseDistanceScaleFactor);
        m_Thresholds[1] = std::max<ScalarType>(m_SeedValue, m_InitialThresholds[1] + (m_ScreenYDifference + m_ScreenXDifference) * m_MouseDistanceScaleFactor);
        MITK_DEBUG << "Screen difference X: " << m_ScreenXDifference;

        // Perform region growing again and show the result
        mitk::Image::Pointer resultImage = mitk::Image::New();
        AccessFixedDimensionByItk_3(m_ReferenceSlice, StartRegionGrowing, 2, indexInWorkingSlice2D, m_Thresholds, resultImage);
        resultImage->SetGeometry(workingSliceGeometry);

        // Update the contour
        if (resultImage.IsNotNull() && m_ConnectedComponentValue >= 1)
        {
            mitk::ImageToContourModelFilter::Pointer contourExtractor = mitk::ImageToContourModelFilter::New();
            contourExtractor->SetInput(resultImage);
            contourExtractor->SetContourValue(m_ConnectedComponentValue - 0.5);
            contourExtractor->Update();
            ContourModel::Pointer resultContour = ContourModel::New();
            resultContour = contourExtractor->GetOutput();

            // Show contour
            if (resultContour.IsNotNull())
            {
                ContourModel::Pointer resultContourWorld = FeedbackContourTool::BackProjectContourFrom2DSlice(workingSliceGeometry, FeedbackContourTool::ProjectContourTo2DSlice(m_WorkingSlice, resultContour));
                FeedbackContourTool::SetFeedbackContour(resultContourWorld);
                FeedbackContourTool::SetFeedbackContourVisible(true);
                mitk::RenderingManager::GetInstance()->ForceImmediateUpdate(positionEvent->GetSender()->GetRenderWindow());
            }
        }
    }
}
/**
 If the feedback contour should be filled, then it is done here. (Contour is NOT filled, when skeletonization is done but no nice cut was found)
*/
bool mitk::RegionGrowingTool::OnMouseReleased( StateMachineAction*, InteractionEvent* interactionEvent )
{
  if ( FeedbackContourTool::CanHandleEvent(interactionEvent) > 0.0 )
  {
    // 1. If we have a working slice, use the contour to fill a new piece on segmentation on it (or erase a piece that was selected by ipMITKSegmentationGetCutPoints)
    if ( m_WorkingSlice.IsNotNull() && m_OriginalPicSlice )
    {
      mitk::InteractionPositionEvent* positionEvent = dynamic_cast<mitk::InteractionPositionEvent*>( interactionEvent );
      //const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
      if (positionEvent)
      {
        // remember parameters for next time
        m_InitialLowerThreshold = m_LowerThreshold;
        m_InitialUpperThreshold = m_UpperThreshold;

        int timestep = positionEvent->GetSender()->GetTimeStep();

        if (m_FillFeedbackContour)
        {
          // 3. use contour to fill a region in our working slice
          ContourModel* feedbackContour( FeedbackContourTool::GetFeedbackContour() );
          if (feedbackContour)
          {
            ContourModel::Pointer projectedContour = FeedbackContourTool::ProjectContourTo2DSlice( m_WorkingSlice, feedbackContour, false, false ); // false: don't add any 0.5
                                                                                                                                    // false: don't constrain the contour to the image's inside
            if (projectedContour.IsNotNull())
            {
              FeedbackContourTool::FillContourInSlice( projectedContour, timestep, m_WorkingSlice, m_PaintingPixelValue );

              const PlaneGeometry* planeGeometry( dynamic_cast<const PlaneGeometry*> (positionEvent->GetSender()->GetCurrentWorldGeometry2D() ) );

              //MITK_DEBUG << "OnMouseReleased: writing back to dimension " << affectedDimension << ", slice " << affectedSlice << " in working image" << std::endl;

             // 4. write working slice back into image volume
             this->WriteBackSegmentationResult(positionEvent, m_WorkingSlice);
            }
          }
        }

        FeedbackContourTool::SetFeedbackContourVisible(false);
        mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() );
      }
    }
  }

  m_ReferenceSlice = NULL; // don't leak
  m_WorkingSlice = NULL;
  m_OriginalPicSlice = NULL;

  return true;
}
void mitk::RegionGrowingTool::OnMousePressedOutside(StateMachineAction*, InteractionEvent* interactionEvent)
{
    mitk::InteractionPositionEvent* positionEvent = dynamic_cast<mitk::InteractionPositionEvent*>(interactionEvent);

    if (positionEvent)
    {
        // Get geometry and indices
        mitk::BaseGeometry::Pointer workingSliceGeometry;
        workingSliceGeometry = m_WorkingSlice->GetTimeGeometry()->GetGeometryForTimeStep(m_LastEventSender->GetTimeStep());
        itk::Index<2> indexInWorkingSlice2D;
        indexInWorkingSlice2D[0] = m_SeedPoint[0];
        indexInWorkingSlice2D[1] = m_SeedPoint[1];

        mitk::BaseGeometry::Pointer referenceSliceGeometry;
        referenceSliceGeometry = m_ReferenceSlice->GetTimeGeometry()->GetGeometryForTimeStep(m_LastEventSender->GetTimeStep());
        itk::Index<3> indexInReferenceSlice;
        itk::Index<2> indexInReferenceSlice2D;
        referenceSliceGeometry->WorldToIndex(positionEvent->GetPositionInWorld(), indexInReferenceSlice);
        indexInReferenceSlice2D[0] = indexInReferenceSlice[0];
        indexInReferenceSlice2D[1] = indexInReferenceSlice[1];

        // Get seed neighborhood
        ScalarType averageValue(0);
        AccessFixedDimensionByItk_3(m_ReferenceSlice, GetNeighborhoodAverage, 2, indexInReferenceSlice2D, &averageValue, 1);
        m_SeedValue = averageValue;
        MITK_DEBUG << "Seed value is " << m_SeedValue;

        // Get level window settings
        LevelWindow lw(0, 500); // default window 0 to 500, can we do something smarter here?
        m_ToolManager->GetReferenceData(0)->GetLevelWindow(lw); // will fill lw if levelwindow property is present, otherwise won't touch it.
        ScalarType currentVisibleWindow = lw.GetWindow();
        MITK_DEBUG << "Level window width is " << currentVisibleWindow;
        m_InitialThresholds[0] = m_SeedValue - currentVisibleWindow / 20.0; // 20 is arbitrary (though works reasonably well), is there a better alternative (maybe option in preferences)?
        m_InitialThresholds[1] = m_SeedValue + currentVisibleWindow / 20.0;
        m_Thresholds[0] = m_InitialThresholds[0];
        m_Thresholds[1] = m_InitialThresholds[1];

        // Perform region growing
        mitk::Image::Pointer resultImage = mitk::Image::New();
        AccessFixedDimensionByItk_3(m_ReferenceSlice, StartRegionGrowing, 2, indexInWorkingSlice2D, m_Thresholds, resultImage);
        resultImage->SetGeometry(workingSliceGeometry);

        // Extract contour
        if (resultImage.IsNotNull() && m_ConnectedComponentValue >= 1)
        {
            mitk::ImageToContourModelFilter::Pointer contourExtractor = mitk::ImageToContourModelFilter::New();
            contourExtractor->SetInput(resultImage);
            contourExtractor->SetContourValue(m_ConnectedComponentValue - 0.5);
            contourExtractor->Update();
            ContourModel::Pointer resultContour = ContourModel::New();
            resultContour = contourExtractor->GetOutput();

            // Show contour
            if (resultContour.IsNotNull())
            {
                ContourModel::Pointer resultContourWorld = FeedbackContourTool::BackProjectContourFrom2DSlice(workingSliceGeometry, FeedbackContourTool::ProjectContourTo2DSlice(m_WorkingSlice, resultContour));
                FeedbackContourTool::SetFeedbackContour(resultContourWorld);
                FeedbackContourTool::SetFeedbackContourVisible(true);
                mitk::RenderingManager::GetInstance()->RequestUpdate(m_LastEventSender->GetRenderWindow());
            }
        }
    }
}