#include #include #include #include #include #include #include #include #include #include // ------------------------------------------------------------------------- cpExtensions::Visualization::ImageSliceActors:: Self* cpExtensions::Visualization::ImageSliceActors:: New( ) { return( new Self( ) ); } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: Clear( ) { this->RemoveAllItems( ); // Main image this->m_Mapper = vtkSmartPointer< vtkImageSliceMapper >::New( ); this->m_Actor = vtkSmartPointer< vtkImageActor >::New( ); this->m_Actor->SetMapper( this->m_Mapper ); // Cursor this->m_Cursor.Create( ); this->m_Cursor.Actor->GetProperty( )->SetColor( 1, 1, 0 ); // Text this->m_TextBuffer[ 0 ] = '\0'; this->m_TextActor = vtkSmartPointer< vtkTextActor >::New( ); this->m_TextActor->SetTextScaleModeToNone( ); vtkTextProperty* textprop = this->m_TextActor->GetTextProperty( ); textprop->SetColor( 1, 1, 0 ); textprop->SetFontFamilyToCourier( ); textprop->SetFontSize( 18 ); textprop->BoldOff( ); textprop->ItalicOff( ); textprop->ShadowOff( ); textprop->SetJustificationToLeft( ); textprop->SetVerticalJustificationToBottom( ); vtkCoordinate* coord = this->m_TextActor->GetPositionCoordinate( ); coord->SetCoordinateSystemToNormalizedViewport( ); coord->SetValue( 0.01, 0.05 ); // Configure style vtkSmartPointer< TStyle > st = vtkSmartPointer< TStyle >::New( ); st->SetAssociatedObject( this ); st->AddMouseMoveCommand( Self::_MouseMoveCommand, this ); st->AddMouseClickCommand( Self::_MouseClickCommand, this ); st->AddMouseWheelCommand( Self::_MouseWheelCommand, this ); st->AddKeyCommand( Self::_KeyCommand, this ); st->AddEnterCommand( Self::_EnterCommand, this ); st->AddLeaveCommand( Self::_LeaveCommand, this ); this->m_Style = st; } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: SetInputConnection( vtkAlgorithmOutput* aout, int orientation ) { if( aout == NULL ) return; this->m_Mapper->SetInputConnection( aout ); this->_ConfigureInput( orientation ); } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: SetInputData( vtkImageData* data, int orientation ) { if( data == NULL ) return; this->m_Mapper->SetInputData( data ); this->_ConfigureInput( orientation ); } // ------------------------------------------------------------------------- vtkImageData* cpExtensions::Visualization::ImageSliceActors:: GetInputData( ) { if( this->m_Mapper.GetPointer( ) != NULL ) return( this->m_Mapper->GetInput( ) ); else return( NULL ); } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: AddMesh( vtkPolyData* mesh ) { SourceActor< vtkCutter > a; a.Create( ); a.Source->SetInputData( mesh ); a.Source->SetCutFunction( this->m_Mapper->GetSlicePlane( ) ); a.Source->SetValue( 0, 0 ); a.Source->GenerateTrianglesOff( ); a.Source->Update( ); a.Modified( ); this->m_Meshes[ mesh ] = a; this->AddItem( a.Actor ); auto ren = this->m_Style->GetCurrentRenderer( ); if( ren != NULL ) if( ren->HasViewProp( this->m_Actor ) ) ren->AddViewProp( a.Actor ); } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: AssociateSlice( Self* slice ) { this->m_AssociatedSlices.push_back( slice ); this->Modified( ); } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: CleanAssociatedSlices( ) { this->m_AssociatedSlices.clear( ); this->Modified( ); } // ------------------------------------------------------------------------- cpExtensions::Interaction::ImageInteractorStyle* cpExtensions::Visualization::ImageSliceActors:: GetStyle( ) { return( dynamic_cast< TStyle* >( this->m_Style.GetPointer( ) ) ); } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: SetStyle( vtkInteractorStyle* st ) { this->m_Style = st; this->Modified( ); } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: PushInto( vtkRenderer* ren ) { this->InitTraversal( ); vtkProp* prop; while( ( prop = this->GetNextProp( ) ) != NULL ) ren->AddViewProp( prop ); } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: PopFrom( vtkRenderer* ren ) { this->InitTraversal( ); vtkProp* prop; while( ( prop = this->GetNextProp( ) ) != NULL ) ren->RemoveViewProp( prop ); } // ------------------------------------------------------------------------- long cpExtensions::Visualization::ImageSliceActors:: GetSliceNumber( ) const { if( this->m_Mapper.GetPointer( ) != NULL ) return( this->m_Mapper->GetSliceNumber( ) ); else return( -1 ); } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: SetSliceNumber( long slice ) { if( this->m_Mapper.GetPointer( ) == NULL ) return; // Get orientation int a = this->m_Mapper->GetOrientation( ); // Check extent int ext[ 6 ]; this->m_Mapper->GetInput( )->GetExtent( ext ); long rs = slice; rs = ( rs > ext[ a << 1 ] )? rs: ext[ a << 1 ]; rs = ( rs < ext[ ( a << 1 ) + 1 ] )? rs: ext[ ( a << 1 ) + 1 ]; // Update pipeline this->m_Mapper->SetSliceNumber( rs ); // Update display extent (this isn't done automatically) ext[ a << 1 ] = ext[ ( a << 1 ) + 1 ] = rs; this->m_Actor->SetDisplayExtent( ext ); this->m_Mapper->Modified( ); this->m_Actor->Modified( ); this->_ConfigureCursor( ); this->Modified( ); } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: ShowPixelText( double* pos ) { if( this->m_Mapper.GetPointer( ) != NULL ) { char axis; int axId = this->m_Mapper->GetOrientation( ); if ( axId == 0 ) axis = 'X'; else if( axId == 1 ) axis = 'Y'; else if( axId == 2 ) axis = 'Z'; long slice = this->GetSliceNumber( ); vtkImageData* image = this->m_Actor->GetInput( ); int ijk[ 3 ]; double pcoords[ 3 ]; image->ComputeStructuredCoordinates( pos, ijk, pcoords ); ijk[ axId ] = slice; int ext[ 6 ]; image->GetExtent( ext ); if( ext[ 0 ] <= ijk[ 0 ] && ijk[ 0 ] <= ext[ 1 ] && ext[ 2 ] <= ijk[ 1 ] && ijk[ 1 ] <= ext[ 3 ] && ext[ 4 ] <= ijk[ 2 ] && ijk[ 2 ] <= ext[ 5 ] ) { int nScl = image->GetNumberOfScalarComponents( ); std::stringstream str; str << "[" << ijk[ 0 ] << "," << ijk[ 1 ] << "," << ijk[ 2 ] << "]=("; str << image->GetScalarComponentAsFloat( ijk[ 0 ], ijk[ 1 ], ijk[ 2 ], 0 ); for( int n = 1; n < nScl; ++n ) str << " " << image->GetScalarComponentAsFloat( ijk[ 0 ], ijk[ 1 ], ijk[ 2 ], n ); str << ")"; #if defined(WIN32) sprintf_s( this->m_TextBuffer, MAX_TEXT_BUFFER, "Axis: %c (%d)\nPixel %s", axis, slice, str.str( ).c_str( ) ); #else // defined(WIN32) std::sprintf( this->m_TextBuffer, "Axis: %c (%ld)\nPixel %s", axis, slice, str.str( ).c_str( ) ); #endif // defined(WIN32) } // fi } else this->m_TextBuffer[ 0 ] = '\0'; this->m_TextActor->SetInput( this->m_TextBuffer ); this->m_TextActor->Modified( ); this->Modified( ); } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: GetScalarRange( double r[ 2 ] ) const { r[ 0 ] = this->m_ScalarRange[ 0 ]; r[ 1 ] = this->m_ScalarRange[ 1 ]; } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: SetScalarRange( const double& a, const double& b ) { this->m_ManualScalarRange = true; this->m_ScalarRange[ 0 ] = a; this->m_ScalarRange[ 1 ] = b; this->SetWindowLevel( 1, 0.5 ); } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: UnsetScalarRange( ) { auto image = this->m_Actor->GetInput( ); if( image != NULL ) { double r[ 2 ]; image->GetScalarRange( r ); this->SetScalarRange( r[ 0 ], r[ 1 ] ); } // fi this->m_ManualScalarRange = false; } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: SetWindowLevel( const double& w, const double& l ) { static const double _0 = double( 0 ); static const double _1 = double( 1 ); double rw = ( w < _0 )? _0: ( ( w > _1 )? _1: w ); double rl = ( l < _0 )? _0: ( ( l > _1 )? _1: l ); double d = this->m_ScalarRange[ 1 ] - this->m_ScalarRange[ 0 ]; rw *= d; rl *= d; rl += this->m_ScalarRange[ 0 ]; if( this->m_Actor.GetPointer( ) != NULL ) { this->m_Actor->GetProperty( )->SetColorWindow( rw ); this->m_Actor->GetProperty( )->SetColorLevel( rl ); this->Modified( ); } // fi } // ------------------------------------------------------------------------- double cpExtensions::Visualization::ImageSliceActors:: GetWindow( ) const { if( this->m_Actor.GetPointer( ) != NULL ) return( this->m_Actor->GetProperty( )->GetColorWindow( ) ); else return( double( 0 ) ); } // ------------------------------------------------------------------------- double cpExtensions::Visualization::ImageSliceActors:: GetLevel( ) const { if( this->m_Actor.GetPointer( ) != NULL ) return( this->m_Actor->GetProperty( )->GetColorLevel( ) ); else return( double( 0 ) ); } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: Render( ) { auto ren = this->m_Style->GetCurrentRenderer( ); if( ren == NULL ) return; auto win = ren->GetRenderWindow( ); if( win == NULL ) return; win->Render( ); } // ------------------------------------------------------------------------- cpExtensions::Visualization::ImageSliceActors:: ImageSliceActors( ) : Superclass( ), m_ManualScalarRange( false ) { this->Clear( ); } // ------------------------------------------------------------------------- cpExtensions::Visualization::ImageSliceActors:: ~ImageSliceActors( ) { } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: _ConfigureInput( int orientation ) { // Prepare main image this->m_Mapper->SetOrientation( orientation ); this->m_Mapper->Update( ); this->m_Actor->GetProperty( )->SetOpacity( 0.8 ); this->m_Actor->Modified( ); auto st = this->GetStyle( ); if( st != NULL ) st->AssociateImageActor( this->m_Actor ); this->AddItem( this->m_Actor ); // Prepare main cursor this->_ConfigureCursor( ); this->AddItem( this->m_Cursor.Actor ); // Prepare window/level if( !( this->m_ManualScalarRange ) ) this->UnsetScalarRange( ); // Add all other actors this->AddItem( this->m_TextActor ); // Put it in the first slice auto image = this->m_Mapper->GetInput( ); int ext[ 6 ]; image->GetExtent( ext ); this->SetSliceNumber( ext[ orientation << 1 ] ); /* if( this->m_Style.GetPointer( ) != NULL ) this->AddItem( this->m_Actor ); this->SetSliceNumber( this->GetSliceNumberMinValue( ) ); this->ResetCursor( ); this->Modified( ); // Reset cursors this->ResetCursor( ); this->ResetAxesCursor( ); // Update window/level ranges vtkImageData* data = this->GetInputImage( ); if( data != NULL ) { double r[ 2 ]; data->GetScalarRange( r ); this->m_WLRange[ 0 ] = double( 0 ); this->m_WLRange[ 1 ] = r[ 1 ] - r[ 0 ]; this->m_WLRange[ 2 ] = r[ 0 ]; this->m_WLRange[ 3 ] = r[ 1 ]; this->ResetWindowLevel( ); // Configure blender this->m_BlenderBase = vtkSmartPointer< vtkImageData >::New( ); this->m_BlenderBase->ShallowCopy( data ); this->m_BlenderBase->AllocateScalars( VTK_UNSIGNED_CHAR, 1 ); std::memset( this->m_BlenderBase->GetScalarPointer( ), 0, this->m_BlenderBase->GetActualMemorySize( ) ); this->m_Blender->AddInputData( this->m_BlenderBase ); } // fi */ } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: _ConfigureCursor( ) { int a = this->m_Mapper->GetOrientation( ); double bounds[ 6 ]; this->m_Actor->GetBounds( bounds ); bounds[ a << 1 ] += 1e-5; bounds[ ( a << 1 ) + 1 ] += 1e-5; this->m_Cursor.Source->SetModelBounds( bounds ); this->m_Cursor.Source->AllOn( ); this->m_Cursor.Actor->GetProperty( )->SetOpacity( 1 ); this->m_Cursor.Actor->GetProperty( )->SetLineWidth( 3 ); this->m_Cursor.Modified( ); } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: _MouseMoveCommand( void* data, const TStyle::ButtonID& btn, int* idx, double* pos, bool alt, bool ctr, bool sft ) { ImageSliceActors* self = reinterpret_cast< ImageSliceActors* >( data ); if( self == NULL ) return; if( btn == TStyle::ButtonID_None ) { self->ShowPixelText( pos ); self->m_Cursor.Source->SetFocalPoint( pos ); self->m_Cursor.Source->Modified( ); self->m_Cursor.Modified( ); self->Render( ); } else if( btn == TStyle::ButtonID_Right ) { if( !alt && !ctr && sft ) { int a0 = self->m_Mapper->GetOrientation( ); int a1 = ( a0 + 1 ) % 3; int a2 = ( a0 + 2 ) % 3; double dx = pos[ a1 ] - self->m_StartMouseEvent[ a1 ]; double dy = pos[ a2 ] - self->m_StartMouseEvent[ a2 ]; double bounds[ 6 ]; self->m_Actor->GetBounds( bounds ); dx /= bounds[ ( a1 << 1 ) + 1 ] - bounds[ a1 << 1 ]; dy /= bounds[ ( a2 << 1 ) + 1 ] - bounds[ a2 << 1 ]; double w = self->m_StartWindow + dx; double l = self->m_StartLevel + dy; self->SetWindowLevel( w, l ); self->Render( ); for( auto aIt = self->m_AssociatedSlices.begin( ); aIt != self->m_AssociatedSlices.end( ); ++aIt ) { ( *aIt )->SetWindowLevel( w, l ); ( *aIt )->Render( ); } // rof } // fi } // fi } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: _MouseClickCommand( void* data, const TStyle::ButtonID& btn, int* idx, double* pos, bool alt, bool ctr, bool sft ) { ImageSliceActors* self = reinterpret_cast< ImageSliceActors* >( data ); if( self == NULL ) return; self->m_StartMouseEvent[ 0 ] = pos[ 0 ]; self->m_StartMouseEvent[ 1 ] = pos[ 1 ]; self->m_StartMouseEvent[ 2 ] = pos[ 2 ]; if( btn == TStyle::ButtonID_Right ) { if( !alt && !ctr && sft ) { double r[ 2 ]; self->GetScalarRange( r ); double d = r[ 1 ] - r[ 0 ]; self->m_StartWindow = self->GetWindow( ) / d; self->m_StartLevel = ( self->GetLevel( ) - r[ 0 ] ) / d; } // fi } // fi } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: _MouseWheelCommand( void* data, const int& dir, bool alt, bool ctr, bool sft ) { ImageSliceActors* self = reinterpret_cast< ImageSliceActors* >( data ); if( self == NULL ) return; auto ren = self->m_Style->GetCurrentRenderer( ); if( ren == NULL ) return; auto cam = ren->GetActiveCamera( ); if( cam == NULL ) return; auto win = ren->GetRenderWindow( ); if( win == NULL ) return; // Get previous values int a = self->m_Mapper->GetOrientation( ); double bounds[ 6 ]; self->m_Actor->GetBounds( bounds ); double prev_pos = bounds[ a << 1 ]; // Move slice long slice = self->GetSliceNumber( ) + dir * ( ( sft )? 10: 1 ); self->SetSliceNumber( slice ); self->m_Actor->GetBounds( bounds ); // Reset camera double cam_pos[ 3 ]; cam->GetPosition( cam_pos ); cam_pos[ a ] += bounds[ a << 1 ] - prev_pos; cam->SetPosition( cam_pos ); // Update text self->ShowPixelText( self->m_Cursor.Source->GetFocalPoint( ) ); // Update all win->Render( ); for( auto aIt = self->m_AssociatedSlices.begin( ); aIt != self->m_AssociatedSlices.end( ); ++aIt ) { if( ( *aIt )->m_Mapper->GetOrientation( ) == a ) { ( *aIt )->SetSliceNumber( slice ); ( *aIt )->Render( ); } // fi } // fi } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: _KeyCommand( void* data, const char& key ) { } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: _EnterCommand( void* data ) { } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: _LeaveCommand( void* data ) { } // eof - $RCSfile$