diff --git a/Modules/ExampleModule/src/ExampleImageInteractor.cpp b/Modules/ExampleModule/src/ExampleImageInteractor.cpp index 93b3b11..0f10950 100644 --- a/Modules/ExampleModule/src/ExampleImageInteractor.cpp +++ b/Modules/ExampleModule/src/ExampleImageInteractor.cpp @@ -1,182 +1,206 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include #include namespace { // Helper function to get an image from a data node. mitk::Image::Pointer GetImage(mitk::DataNode::Pointer dataNode) { if (dataNode.IsNull()) mitkThrow(); mitk::Image::Pointer image = dynamic_cast(dataNode->GetData()); if (image.IsNull()) mitkThrow(); return image; } // Helper function to get a geometry of an image for a specific time step. mitk::BaseGeometry::Pointer GetGeometry(mitk::Image::Pointer image, unsigned int timeStep) { mitk::TimeGeometry::Pointer timeGeometry = image->GetTimeGeometry(); if (timeGeometry.IsNull()) mitkThrow(); auto geometry = timeGeometry->GetGeometryForTimeStep(timeStep); if (geometry.IsNull()) mitkThrow(); return geometry; } } // The actual painting happens here. We're using a write accessor to gain safe // write access to our image. The whole image volume for a given time step is // locked. However, it's also possible - and preferable - to lock the slice of // interest only. template static void Paint(mitk::Image::Pointer image, itk::Index<3> index, unsigned int timeStep) { // As soon as the ImagePixelWriteAccessor object goes out of scope at the // end of this function, the image will be unlocked again (RAII). mitk::ImagePixelWriteAccessor writeAccessor(image, image->GetVolumeData(timeStep)); writeAccessor.SetPixelByIndex(index, std::numeric_limits::min()); // Don't forget to update the modified time stamp of the image. Otherwise, // everything downstream wouldn't recognize that the image changed, // including the rendering system. image->Modified(); } // Helper function to multiplex the actual Paint function call for different // pixel types. As it's cumbersome and ugly, you may want to avoid such // functions by using ITK for the actual painting and use the ITK access // macros like we did for the AwesomeImageFilter. static void Paint(mitk::Image::Pointer image, itk::Index<3> index, unsigned int timeStep) { switch (image->GetPixelType().GetComponentType()) { +#if ITK_VERSION_MAJOR < 5 case itk::ImageIOBase::CHAR: +#else + case itk::IOComponentEnum::CHAR: +#endif Paint(image, index, timeStep); break; +#if ITK_VERSION_MAJOR < 5 case itk::ImageIOBase::UCHAR: +#else + case itk::IOComponentEnum::UCHAR: +#endif Paint(image, index, timeStep); break; +#if ITK_VERSION_MAJOR < 5 case itk::ImageIOBase::SHORT: +#else + case itk::IOComponentEnum::SHORT: +#endif Paint(image, index, timeStep); break; +#if ITK_VERSION_MAJOR < 5 case itk::ImageIOBase::USHORT: +#else + case itk::IOComponentEnum::USHORT: +#endif Paint(image, index, timeStep); break; +#if ITK_VERSION_MAJOR < 5 case itk::ImageIOBase::INT: +#else + case itk::IOComponentEnum::INT: +#endif Paint(image, index, timeStep); break; +#if ITK_VERSION_MAJOR < 5 case itk::ImageIOBase::UINT: +#else + case itk::IOComponentEnum::UINT: +#endif Paint(image, index, timeStep); break; default: mitkThrow(); } } ExampleImageInteractor::ExampleImageInteractor() { } ExampleImageInteractor::~ExampleImageInteractor() { } void ExampleImageInteractor::ConnectActionsAndFunctions() { // Wire up this interactor with the state machine that is described by // resource/Interactions/Paint.xml. CONNECT_FUNCTION("paint", Paint) } void ExampleImageInteractor::DataNodeChanged() { // You almost always want to reset the state machine when the interactor // has been attached to another data node. this->ResetToStartState(); } // The state machine is wired up with this Paint method. We wrote a few helper // functions at the top of this files to keep this method clear and easy to // read. void ExampleImageInteractor::Paint(mitk::StateMachineAction*, mitk::InteractionEvent* event) { try { auto renderer = event->GetSender(); auto image = GetImage(this->GetDataNode()); auto timeStep = renderer->GetTimeStep(); auto geometry = GetGeometry(image, timeStep); // This method is wired up to mouse events. Thus, we can safely assume // that the following cast will succeed and we have access to the mouse // position and the first intersection point of a ray originating at the // mouse position and shot into the scene. Convenient, isn't it? :-) auto positionEvent = dynamic_cast(event); auto position = positionEvent->GetPositionInWorld(); if (!geometry->IsInside(position)) return; // Nothing to paint, as we're not inside the image bounds. // Okay, we're safe. Convert the mouse position to the index of the pixel // we're pointing at. itk::Index<3> index; geometry->WorldToIndex<3>(position, index); // We don't need to paint over and over again while moving the mouse // pointer inside the same pixel. That's especially relevant when operating // on zoomed images. if (index != m_LastPixelIndex) { // And finally... ::Paint(image, index, timeStep); // Nearly done. We request the renderer to update the render window in // order to see the result immediately. Actually, we should update all // of the render windows by caling RequestUpdateAll() instead, as the // painted pixels are possibly visible in other render windows, too. // However, we decided to prefer performance here. mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow()); MITK_INFO << index[0] << " " << index[1] << " " << index[2]; m_LastPixelIndex = index; } } catch (...) { return; } }