NIREP
|
00001 /*========================================================================= 00002 00003 Program: vtkINRIA3D 00004 Module: $Id: Checkerboard.cxx,v 1.19 2011/02/08 21:07:53 hawle Exp $ 00005 Language: C++ 00006 Author: $Author: hawle $ 00007 Date: $Date: 2011/02/08 21:07:53 $ 00008 Version: $Revision: 1.19 $ 00009 00010 Copyright (c) 2007 INRIA - Asclepios Project. All rights reserved. 00011 See Copyright.txt for details. 00012 00013 This software is distributed WITHOUT ANY WARRANTY; without even 00014 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 00015 PURPOSE. See the above copyright notices for more information. 00016 00017 =========================================================================*/ 00018 #include "Checkerboard.h" 00019 00020 #include "vtkInteractorObserver.h" 00021 #include "vtkInteractorStyleSwitch.h" 00022 #include "vtkRenderer.h" 00023 #include "vtkRenderWindow.h" 00024 #include "vtkRenderWindowInteractor.h" 00025 #include "vtkRendererCollection.h" 00026 #include "vtkProp.h" 00027 #include "vtkTextActor.h" 00028 #include "vtkCoordinate.h" 00029 #include "vtkProperty.h" 00030 #include "vtkProperty2D.h" 00031 #include "vtkTextProperty.h" 00032 #include <vtkCornerAnnotation.h> 00033 #include <vtkLightCollection.h> 00034 #include <vtkLight.h> 00035 #include "vtkOrientationAnnotation.h" 00036 00037 #include "assert.h" 00038 #include <iostream> 00039 #include <sstream> 00040 #include <cmath> 00041 00042 #include "NIREPvtkViewImage2DCommand.h" 00043 #include "vtkViewImage2DFullCommand.h" 00044 #include "NIREPvtkInteractorStyleImage2D.h" 00045 #include "vtkCamera.h" 00046 #include "vtkImageReslice.h" 00047 #include "vtkRenderWindow.h" 00048 #include "vtkTransform.h" 00049 #include "vtkImageMapToWindowLevelColors.h" 00050 #include "vtkImageMapToColors.h" 00051 #include "vtkImageActor.h" 00052 #include "vtkImageData.h" 00053 #include "vtkActor.h" 00054 #include "vtkPolyDataMapper.h" 00055 #include "vtkLineSource.h" 00056 #include "vtkLookupTable.h" 00057 #include "vtkImageBlendWithMask.h" 00058 #include "vtkImageBlend.h" 00059 #include <vtkPolyDataMapper2D.h> 00060 #include <vtkActor2D.h> 00061 00062 #include <vtkColorTransferFunction.h> 00063 #include <vtkDataArray.h> 00064 #include <vtkPointData.h> 00065 #include <vtkCellData.h> 00066 #include <vtkExtractGeometry.h> 00067 #include <vtkDataSet.h> 00068 #include <vtkUnstructuredGrid.h> 00069 #include <vtkDataSetMapper.h> 00070 #include <vtkPlane.h> 00071 #include <vtkPlaneCollection.h> 00072 #include <vtkPolyDataMapper2D.h> 00073 #include <vtkActor2D.h> 00074 #include <vtkClipDataSet.h> 00075 #include <vtkCutter.h> 00076 #include <vtkBox.h> 00077 #include <vtkPolyDataWriter.h> 00078 #include <vtkPolyDataNormals.h> 00079 #include <vtkTransform.h> 00080 #include <vtkMath.h> 00081 #include <vtkRulerWidget.h> 00082 00083 //Jeffrey Hawley added this 00084 #include "vtkCheckerboardWidget.h" 00085 #include "vtkImageCheckerboard.h" 00086 #include "vtkCheckerboardRepresentation.h" 00087 //end of addition 00088 00089 vtkCxxRevisionMacro(Checkerboard, "$Revision: 1.19 $"); 00090 vtkStandardNewMacro(Checkerboard); 00091 00092 00093 Checkerboard::Checkerboard():NIREPvtkViewImage2D() 00094 { 00095 //Jeffrey Hawley added this 00096 this->SecondImage = NULL; 00097 this->CheckerboardWidget = vtkCheckerboardWidget::New(); 00098 this->ImageCheckerboard = vtkImageCheckerboard::New(); 00099 this->CheckerboardRepresentation = vtkCheckerboardRepresentation::New(); 00100 this->ImageCheckerboard->SetNumberOfDivisions(2,2,1); 00101 //end of addition 00102 00103 this->ImageResliceTwo = vtkImageReslice::New(); 00104 00105 this->CheckerboardRepresentation->SetImageActor(this->ImageActor); 00106 this->CheckerboardRepresentation->SetCheckerboard(this->ImageCheckerboard); 00107 00108 this->CheckerboardWidget->SetCurrentRenderer(this->GetRenderer()); 00109 00110 this->CheckerboardWidget->SetRepresentation(this->CheckerboardRepresentation); 00111 00112 //for some reason if we take this out, then the image does not show up 00113 //I wonder if this will work 00114 this->GetWindowLevel()->Delete(); 00115 this->WindowLevel = vtkImageMapToColors::New(); 00116 this->ImageReslice->SetInputConnection( this->WindowLevel->GetOutputPort() ); 00117 00118 00119 this->WindowLevelTwo = vtkImageMapToColors::New(); 00120 this->MaskFilterTwo = vtkImageBlendWithMask::New(); 00121 00122 00123 this->ImageResliceTwo->SetOutputDimensionality(2); 00124 this->ImageResliceTwo->InterpolateOff(); 00125 this->ImageResliceTwo->SetInputConnection( this->WindowLevelTwo->GetOutputPort() ); 00126 00127 00128 this->AuxInputTwo = this->WindowLevelTwo->GetOutput(); 00129 this->ResliceInputTwo = this->WindowLevelTwo->GetOutput(); 00130 00131 00132 00133 00134 } 00135 00136 00137 Checkerboard::~Checkerboard() 00138 { 00139 this->CheckerboardWidget->EnabledOff(); 00140 this->CheckerboardWidget->Delete(); 00141 this->ImageCheckerboard->Delete(); 00142 this->CheckerboardRepresentation->Delete(); 00143 00144 this->WindowLevelTwo->Delete(); 00145 this->ImageResliceTwo->Delete(); 00146 this->SecondImage->UnRegister(this); 00147 00148 this->MaskFilterTwo->Delete(); 00149 } 00150 00151 //void Checkerboard::InternalUpdate() 00152 //{ 00153 // this->UpdateImageActor(); 00154 // //this->UpdatePosition(); 00155 // this->InitializeImagePositionAndSize(); 00156 // 00157 // // this->UpdatePosition(); 00158 // 00159 //} 00160 00161 00167 //void Checkerboard::Initialize() 00168 //{ 00169 // this->Superclass::Initialize(); 00170 // 00171 // if (this->GetRenderer()) 00172 // { 00173 // this->GetRenderer()->TwoSidedLightingOff(); 00174 // } 00175 // 00176 // 00177 //} 00178 00179 00180 void Checkerboard::UpdateImageActor() 00181 { 00182 if(!this->SecondImage) 00183 { 00184 return; 00185 } 00186 if( !this->GetImage() ) 00187 { 00188 return; 00189 } 00190 00196 00197 //Since the image is already in ImageCheckerboard we just have 00198 //to do some updating of the ImageCheckerboard and pass 00199 //the information to the ImageActor. 00200 this->ImageReslice->GetOutput()->UpdateInformation(); 00201 this->ImageResliceTwo->GetOutput()->UpdateInformation(); 00202 this->ImageCheckerboard->GetOutput()->UpdateInformation(); 00203 this->ImageActor->GetInput()->SetUpdateExtent(this->ImageCheckerboard->GetOutput()->GetWholeExtent()); 00204 this->ImageActor->SetDisplayExtent(this->ImageCheckerboard->GetOutput()->GetWholeExtent()); 00205 00206 this->FirstRender = 1; 00207 } 00208 00209 00210 00211 //Changes: 00212 //-Will need to do two ImagesReslices 00213 void Checkerboard::UpdatePosition () 00214 { 00215 if(!this->SecondImage) 00216 { 00217 return; 00218 } 00219 if( !this->GetImage() ) 00220 { 00221 return; 00222 } 00223 00224 double x=0; 00225 double y=0; 00226 double max_x=0; 00227 double max_y=0; 00228 double min_x=0; 00229 double min_y=0; 00230 double pos[4]; 00231 00232 this->GetCurrentPoint(pos); 00233 pos[3] = 0.0; 00234 00235 double* spacing = this->GetImage()->GetSpacing(); 00236 double* origin = this->GetImage()->GetOrigin(); 00237 00238 // check if pos lies inside image bounds 00239 //if( pos[0]<imBounds[0] || pos[0]>imBounds[1] || 00240 // pos[1]<imBounds[2] || pos[1]>imBounds[3] || 00241 // pos[2]<imBounds[4] || pos[2]>imBounds[5]) 00242 //{ 00243 // // we are outside image bounds 00244 // return; 00245 //} 00246 00247 // round to the nearest integer slice 00248 pos[0] = vtkMath::Round ((pos[0]-origin[0])/spacing[0] )*spacing[0]+origin[0]; 00249 pos[1] = vtkMath::Round ((pos[1]-origin[1])/spacing[1] )*spacing[1]+origin[1]; 00250 pos[2] = vtkMath::Round ((pos[2]-origin[2])/spacing[2] )*spacing[2]+origin[2]; 00251 00252 /* 00253 double *bounds = this->ImageActor->GetBounds(); 00254 min_x = bounds[0]; 00255 max_x = bounds[1]; 00256 min_y = bounds[2]; 00257 max_y = bounds[3]; 00258 */ 00259 00260 double min_bounds[4] = { this->GetWholeMinPosition(0), 00261 this->GetWholeMinPosition(1), 00262 this->GetWholeMinPosition(2), 00263 0.0 }; 00264 00265 double max_bounds[4] = { this->GetWholeMaxPosition(0), 00266 this->GetWholeMaxPosition(1), 00267 this->GetWholeMaxPosition(2), 00268 0.0 }; 00269 00270 00271 // new efficient way to get the reslice origin and the axis coordinates. 00272 double reslice[4], pos2[4]; 00273 this->ScreenToRealWorldMatrix->MultiplyPoint (pos, reslice); 00274 this->ImageReslice->SetResliceAxesOrigin(reslice[0], reslice[1], reslice[2]); 00275 this->ImageResliceTwo->SetResliceAxesOrigin(reslice[0], reslice[1], reslice[2]); 00276 00277 00278 vtkMatrix4x4* mat = vtkMatrix4x4::New(); 00279 vtkMatrix4x4::Transpose (this->OrientationMatrix, mat); 00280 mat->MultiplyPoint (pos, pos2); 00281 mat->MultiplyPoint (min_bounds, min_bounds); 00282 mat->MultiplyPoint (max_bounds, max_bounds); 00283 mat->Delete(); 00284 00285 x = pos2[0]; 00286 y = pos2[1]; 00287 00288 max_x = max_bounds[0]; 00289 max_y = max_bounds[1]; 00290 00291 min_x = min_bounds[0]; 00292 min_y = min_bounds[1]; 00293 00294 this->HorizontalLineSource->SetPoint1(min_x, y, 0.001); 00295 this->HorizontalLineSource->SetPoint2(max_x, y, 0.001); 00296 this->VerticalLineSource->SetPoint1(x, min_y, 0.001); 00297 this->VerticalLineSource->SetPoint2(x, max_y, 0.001); 00298 00299 this->ImageReslice->Update(); // needed to update input Extent 00300 this->ImageResliceTwo->Update(); 00301 00302 int imCoor[3]; 00303 this->GetCurrentVoxelCoordinates(imCoor); 00304 int dims[3]; 00305 this->GetImage()->GetDimensions (dims); 00306 00307 std::ostringstream os2; 00308 std::ostringstream os; 00309 //os << "Slice: "; 00310 00311 os2 << "Zoom: " << this->GetZoom()*100.0 << " \%\n"; 00312 00313 switch( this->Orientation ) 00314 { 00315 case NIREPvtkViewImage::AXIAL_ID : 00316 os << "Image size: " << dims[0] << " x " << dims[1] << "\n"; 00317 os << "Voxel size: " << spacing[0] << " x " << spacing[1] << "\n"; 00318 //os << imCoor[2] << " / " << dims[2]-1 << std::endl; 00319 os << "X: " << imCoor[0] << " px Y: " << imCoor[1] << " px Value: " 00320 << this->GetCurrentPointDoubleValue() << std::endl; 00321 os << "X: " << pos[0] << " mm Y: " << pos[1] << " mm\n"; 00322 if ( this->ShowSliceNumber ) 00323 os2 << "Slice: " << imCoor[2] << " / " << dims[2]-1 << std::endl; 00324 os2 << "Location: " << pos[2] << " mm"; 00325 break; 00326 00327 00328 case NIREPvtkViewImage::CORONAL_ID : 00329 os << "Image size: " << dims[0] << " x " << dims[2] << "\n"; 00330 os << "Voxel size: " << spacing[0] << " x " << spacing[2] << "\n"; 00331 //os << imCoor[1] << " / " << dims[1]-1 << std::endl; 00332 os << "X: " << imCoor[0] << " px Z: " << imCoor[2] << " px Value: " 00333 << this->GetCurrentPointDoubleValue() << std::endl; 00334 os << "X: " << pos[0] << " mm Z: " << pos[2] << " mm\n"; 00335 if ( this->ShowSliceNumber ) 00336 os2 << "Slice: " << imCoor[1] << " / " << dims[1]-1 << std::endl; 00337 os2 << "Location: " << pos[1] << " mm"; 00338 break; 00339 00340 00341 case NIREPvtkViewImage::SAGITTAL_ID : 00342 os << "Image size: " << dims[1] << " x " << dims[2] << "\n"; 00343 os << "Voxel size: " << spacing[1] << " x " << spacing[2] << "\n"; 00344 //os << imCoor[0] << " / " << dims[0]-1 << std::endl; 00345 os << "Y: " << imCoor[1] << " px Z: " << imCoor[2] << " px Value: " 00346 << this->GetCurrentPointDoubleValue() << std::endl; 00347 os << "Y: " << pos[1] << " mm Z: " << pos[2] << " mm\n"; 00348 if ( this->ShowSliceNumber ) 00349 os2 << "Slice: " << imCoor[0] << " / " << dims[0]-1 << std::endl; 00350 os2 << "Location: " << pos[0] << " mm"; 00351 break; 00352 } 00353 os << "<window_level>"; 00354 00355 this->SetUpLeftAnnotation( os.str().c_str() ); 00356 this->SetDownLeftAnnotation( os2.str().c_str() ); 00357 // } 00358 // else 00359 // this->SetUpRightAnnotation(""); 00360 00361 unsigned int direction = this->GetOrthogonalAxis (this->GetOrientation()); 00362 this->DataSetCutPlane->SetOrigin (reslice[0], reslice[1], reslice[2]); 00363 00364 switch(direction) 00365 { 00366 case X_ID : 00367 //this->DataSetCutPlane->SetNormal (1,0,0); 00368 this->DataSetCutBox->SetBounds (this->DataSetCutPlane->GetOrigin()[0],this->DataSetCutPlane->GetOrigin()[0]+this->BoxThickness, 00369 this->GetWholeMinPosition(1),this->GetWholeMaxPosition(1), 00370 this->GetWholeMinPosition(2),this->GetWholeMaxPosition(2)); 00371 00372 break; 00373 case Y_ID : 00374 //this->DataSetCutPlane->SetNormal (0,1,0); 00375 this->DataSetCutBox->SetBounds (this->GetWholeMinPosition(0),this->GetWholeMaxPosition(0), 00376 this->DataSetCutPlane->GetOrigin()[1],this->DataSetCutPlane->GetOrigin()[1]+this->BoxThickness, 00377 this->GetWholeMinPosition(2),this->GetWholeMaxPosition(2)); 00378 break; 00379 case Z_ID : 00380 //this->DataSetCutPlane->SetNormal (0,0,1); 00381 this->DataSetCutBox->SetBounds (this->GetWholeMinPosition(0),this->GetWholeMaxPosition(0), 00382 this->GetWholeMinPosition(1),this->GetWholeMaxPosition(1), 00383 this->DataSetCutPlane->GetOrigin()[2],this->DataSetCutPlane->GetOrigin()[2]+this->BoxThickness); 00384 break; 00385 } 00386 00387 00388 if( this->DataSetList.size() ) 00389 { 00390 00391 this->ResetAndRestablishZoomAndCamera(); 00392 00393 /* 00394 We need to correct for the origin of the actor. Indeed, the ImageActor 00395 has always position 0 in Z in axial view, in X in sagittal view and 00396 in Y in coronal view. The projected dataset have an origin that depends 00397 on the required slice and can be negative. In that case, the projected 00398 data are behind the image actor and thus not visible. Here, we correct 00399 this by translating the actor so that it becomes visible. 00400 */ 00401 for( unsigned int i=0; i<this->DataSetActorList.size(); i++) 00402 { 00403 double Pos[3]; 00404 this->DataSetActorList[i]->GetPosition (Pos); 00405 00406 switch(direction) 00407 { 00408 case X_ID : 00409 Pos[0] = -1.0*reslice[0] + 1.0; 00410 break; 00411 00412 case Y_ID: 00413 Pos[1] = -1.0*reslice[1] + 1.0; 00414 break; 00415 00416 case Z_ID: 00417 Pos[2] = -1.0*reslice[2] + 1.0; 00418 break; 00419 } 00420 00421 this->DataSetActorList[i]->SetPosition (Pos); 00422 } 00423 00424 } 00425 00426 this->Modified(); 00427 } 00428 00429 00430 00431 void Checkerboard::SetWindow (double w) 00432 { 00433 00434 if( w<0.0 ) 00435 { 00436 w = 0.0; 00437 } 00438 00439 double shiftScaleWindow = this->GetShift() + w*this->GetScale(); 00440 00441 NIREPvtkViewImage::SetWindow ( shiftScaleWindow ); 00442 this->WindowLevelForCorner->SetWindow( shiftScaleWindow ); 00443 00444 double v_min = this->GetLevel() - 0.5*this->GetWindow(); 00445 double v_max = this->GetLevel() + 0.5*this->GetWindow(); 00446 00447 if( this->GetLookupTable() && this->WindowLevel->GetLookupTable()) 00448 { 00449 00450 this->GetLookupTable()->SetRange ( (v_min-0.5*this->GetShift())/this->GetScale(), 00451 (v_max-1.5*this->GetShift())/this->GetScale()); 00452 this->WindowLevel->GetLookupTable()->SetRange (v_min, v_max); 00453 this->WindowLevelTwo->GetLookupTable()->SetRange (v_min, v_max); 00454 } 00455 00456 if(this->BGWindowLevel && this->BGWindowLevel->GetLookupTable()) 00457 this->BGWindowLevel->GetLookupTable()->SetRange( v_min, v_max); 00458 } 00459 00460 00461 00462 void Checkerboard::SetLevel (double l) 00463 { 00464 00465 double shiftScaleLevel = this->GetShift() + l*this->GetScale(); 00466 00467 NIREPvtkViewImage::SetLevel ( shiftScaleLevel ); 00468 this->WindowLevelForCorner->SetLevel( shiftScaleLevel ); 00469 00470 double v_min = this->GetLevel() - 0.5*this->GetWindow(); 00471 double v_max = this->GetLevel() + 0.5*this->GetWindow(); 00472 00473 if( this->GetLookupTable() ) 00474 { 00475 this->GetLookupTable()->SetRange ( (v_min-0.5*this->GetShift())/this->GetScale(), 00476 (v_max-1.5*this->GetShift())/this->GetScale()); 00477 this->WindowLevel->GetLookupTable()->SetRange (v_min, v_max); 00478 this->WindowLevelTwo->GetLookupTable()->SetRange (v_min, v_max); 00479 } 00480 } 00481 00482 00483 //Changes: 00484 //-Probably should get rid of this, but maybe not, will need to dicuss 00485 //to see how we want to deal with overlaps. 00486 void Checkerboard::SetSecondImage (vtkImageData* image) 00487 { 00488 00489 if( !image ) 00490 { 00491 return; 00492 } 00493 00494 if(this->SecondImage != image) 00495 { 00496 if( this->SecondImage != NULL ) 00497 { 00498 this->SecondImage->UnRegister (this); 00499 } 00500 this->SecondImage = image; 00501 this->SecondImage->Register (this); 00502 int type = image->GetScalarType(); 00503 int numberOfScalars = image->GetNumberOfScalarComponents(); 00504 if( image->GetScalarType() == VTK_UNSIGNED_CHAR && (image->GetNumberOfScalarComponents()==3 || image->GetNumberOfScalarComponents()==4) ) 00505 { 00506 this->AuxInputTwo = image; 00507 } 00508 else 00509 //if(!( image->GetScalarType() == VTK_UNSIGNED_CHAR && (image->GetNumberOfScalarComponents()==3 || image->GetNumberOfScalarComponents()==4) )) 00510 { 00511 this->WindowLevelTwo->SetInput (image); 00512 double range[2]; 00513 image->GetScalarRange (range); 00514 if ( this->WindowLevelTwo->GetLookupTable() ) 00515 { 00516 this->WindowLevelTwo->GetLookupTable()->SetRange (range); 00517 } 00518 this->AuxInputTwo = this->WindowLevelTwo->GetOutput(); 00519 } 00520 00521 if( this->GetMaskImage() ) 00522 { 00523 this->MaskFilterTwo->SetImageInput ( this->AuxInputTwo ); 00524 } 00525 else 00526 { 00527 this->ImageResliceTwo->SetInput ( this->AuxInputTwo ); 00528 this->ResliceInputTwo = this->AuxInputTwo; 00529 } 00530 00531 // this->SetOrientation(this->Orientation); 00532 //this->ResliceInput = this->Blender->GetOutput(); 00533 //} 00534 } 00535 00536 if(this->GetImage()) 00537 { 00538 if(this->GetSecondImage()) 00539 { 00540 this->CheckerboardWidget->SetInteractor(this->GetRenderWindow()->GetInteractor()); 00541 this->ImageCheckerboard->SetInput1(this->ImageReslice->GetOutput()); 00542 this->ImageCheckerboard->SetInput2(this->ImageResliceTwo->GetOutput()); 00543 this->ImageCheckerboard->Update(); 00544 this->ImageActor->SetInput(this->ImageCheckerboard->GetOutput()); 00545 this->AddActor(this->ImageActor); 00546 this->CheckerboardWidget->EnabledOn(); 00547 00548 this->AddActor(this->HorizontalLineActor); 00549 this->AddActor(this->VerticalLineActor); 00550 00551 //this->AddActor(this->ImageActor); 00552 00553 00554 00555 // Save the camera focal and position, and zoom, before calling InternalUpdate() 00556 double focal[3], pos[3], zoom; 00557 this->GetCameraFocalAndPosition (focal, pos); 00558 zoom = this->GetZoom(); 00559 00560 00561 this->SetupAnnotations(); 00562 this->InternalUpdate(); 00563 00564 00565 // Check that the current displayed point lies within the bounds of the image. If not, 00566 // we camp it to the nearest acceptable position. 00567 double *wextent = image->GetBounds(); 00568 double position[3]; 00569 this->GetCurrentPoint ( position ); 00570 position[0]<wextent[0]?position[0]=wextent[0]:position[0]; 00571 position[0]>wextent[1]?position[0]=wextent[1]:position[0]; 00572 position[1]<wextent[2]?position[1]=wextent[2]:position[1]; 00573 position[1]>wextent[3]?position[1]=wextent[3]:position[1]; 00574 position[2]<wextent[4]?position[2]=wextent[4]:position[2]; 00575 position[2]>wextent[5]?position[2]=wextent[5]:position[2]; 00576 this->SetCurrentPoint ( position ); 00577 00578 00579 00580 //this->SetWindow( this->GetWindow() ); 00581 //this->SetLevel( this->GetLevel() ); 00582 00583 00584 // restore the zoom and focal in case this is not the first time we render the image. 00585 if( !this->GetFirstImage() ) 00586 { 00587 this->SetZoom ( zoom ); 00588 this->SetCameraFocalAndPosition (focal, pos); 00589 this->SetFirstImage (0); 00590 } 00591 00592 if( this->RulerWidgetVisibility ) 00593 this->RulerWidget->On(); 00594 } 00595 } 00596 00597 } 00598 00599 00600 00601 //Changes: 00602 //-Either need to create another SetImage, or have this SetImage place the images into an array 00603 //-Look into RegisterImage, I might have to do something else. 00604 //-I think I should create another SetImage 00605 void Checkerboard::SetImage(vtkImageData* image) 00606 { 00607 if(!image) 00608 { 00609 return; 00610 } 00611 00612 int* extent = image->GetExtent(); 00613 if( extent[1]<extent[0] || extent[3]<extent[2] || extent[5]<extent[4] ) 00614 { 00615 vtkErrorMacro ( << "Image extent is not valid: " << extent[0] << " " 00616 << extent[1] << " " 00617 << extent[2] << " " 00618 << extent[3] << " " 00619 << extent[4] << " " 00620 << extent[5]); 00621 return; 00622 } 00623 00624 00625 NIREPvtkViewImage::SetImage( image ); 00626 00627 // check if there is a mask image. If yes, then we check 00628 // if the new image size and spacing agrees with the mask image. 00629 // If not, we remove the mask image 00630 if( this->GetMaskImage() ) 00631 { 00632 int* dims = image->GetDimensions(); 00633 double* spacing = image->GetSpacing(); 00634 int* maskDims = this->GetMaskImage()->GetDimensions(); 00635 double* maskSpacing = this->GetMaskImage()->GetSpacing(); 00636 00637 if( dims[0]!=maskDims[0] || dims[1]!=maskDims[1] || dims[2]!=maskDims[2] || 00638 spacing[0]!=maskSpacing[0] || spacing[1]!=maskSpacing[1] || spacing[2]!=maskSpacing[2] ) 00639 { 00640 this->RemoveMaskImage(); 00641 } 00642 } 00643 00644 // should check also the overlapping image 00645 00646 if( image->GetScalarType() == VTK_UNSIGNED_CHAR && (image->GetNumberOfScalarComponents()==3 || image->GetNumberOfScalarComponents()==4) ) 00647 { 00648 this->AuxInput = image; 00649 } 00650 else 00651 { 00652 this->AuxInput = this->WindowLevel->GetOutput(); 00653 00654 this->WindowLevel->SetInput (image); 00655 double range[2]; 00656 image->GetScalarRange (range); 00657 if ( this->WindowLevel->GetLookupTable() ) 00658 { 00659 this->WindowLevel->GetLookupTable()->SetRange (range); 00660 } 00661 } 00662 00663 00664 if( this->GetOverlappingImage() ) 00665 { 00666 this->Blender->SetInput (0, this->AuxInput ); 00667 } 00668 else 00669 { 00670 if( this->GetMaskImage() ) 00671 { 00672 this->MaskFilter->SetImageInput ( this->AuxInput ); 00673 } 00674 else 00675 { 00676 this->ImageReslice->SetInput ( this->AuxInput ); 00677 this->ResliceInput = this->AuxInput; 00678 } 00679 } 00680 00681 //this->ImageActor->SetInput( this->ImageReslice->GetOutput() ); 00682 00683 if(this->GetImage()) 00684 { 00685 if(this->GetSecondImage()) 00686 { 00687 this->CheckerboardWidget->SetInteractor(this->GetRenderWindow()->GetInteractor()); 00688 this->ImageCheckerboard->SetInput1(this->ImageReslice->GetOutput()); 00689 this->ImageCheckerboard->SetInput2(this->ImageResliceTwo->GetOutput()); 00690 this->ImageCheckerboard->Update(); 00691 this->ImageActor->SetInput(this->ImageCheckerboard->GetOutput()); 00692 this->AddActor(this->ImageActor); 00693 this->CheckerboardWidget->EnabledOn(); 00694 00695 00696 00697 this->AddActor(this->HorizontalLineActor); 00698 this->AddActor(this->VerticalLineActor); 00699 00700 //this->AddActor(this->ImageActor); 00701 00702 00703 00704 // Save the camera focal and position, and zoom, before calling InternalUpdate() 00705 double focal[3], pos[3], zoom; 00706 this->GetCameraFocalAndPosition (focal, pos); 00707 zoom = this->GetZoom(); 00708 00709 00710 this->SetupAnnotations(); 00711 this->InternalUpdate(); 00712 00713 00714 // Check that the current displayed point lies within the bounds of the image. If not, 00715 // we camp it to the nearest acceptable position. 00716 double *wextent = image->GetBounds(); 00717 double position[3]; 00718 this->GetCurrentPoint ( position ); 00719 position[0]<wextent[0]?position[0]=wextent[0]:position[0]; 00720 position[0]>wextent[1]?position[0]=wextent[1]:position[0]; 00721 position[1]<wextent[2]?position[1]=wextent[2]:position[1]; 00722 position[1]>wextent[3]?position[1]=wextent[3]:position[1]; 00723 position[2]<wextent[4]?position[2]=wextent[4]:position[2]; 00724 position[2]>wextent[5]?position[2]=wextent[5]:position[2]; 00725 this->SetCurrentPoint ( position ); 00726 00727 00728 // restore the zoom and focal in case this is not the first time we render the image. 00729 if( !this->GetFirstImage() ) 00730 { 00731 this->SetZoom ( zoom ); 00732 this->SetCameraFocalAndPosition (focal, pos); 00733 this->SetFirstImage (0); 00734 } 00735 00736 if( this->RulerWidgetVisibility ) 00737 this->RulerWidget->On(); 00738 00739 } 00740 } 00741 } 00742 00743 void Checkerboard::SetLookupTable (vtkScalarsToColors* lut) 00744 { 00745 00746 if( !lut ) 00747 { 00748 return; 00749 } 00750 00751 NIREPvtkViewImage::SetLookupTable (lut); 00752 00753 double v_min = this->GetLevel() - 0.5*this->GetWindow(); 00754 double v_max = this->GetLevel() + 0.5*this->GetWindow(); 00755 00761 lut->SetRange ( (v_min-0.5*this->GetShift())/this->GetScale(), 00762 (v_max-1.5*this->GetShift())/this->GetScale() ); 00763 00764 00765 vtkLookupTable* realLut = vtkLookupTable::SafeDownCast (lut); 00766 00767 if( !realLut ) 00768 { 00769 std::cerr << "Error: Cannot cast vtkScalarsToColors to vtkLookupTable." << std::endl; 00770 return; 00771 } 00772 00777 vtkLookupTable* newLut = vtkLookupTable::New(); 00778 newLut->DeepCopy (realLut); 00779 newLut->SetRange (v_min, v_max); 00780 this->WindowLevel->SetLookupTable (newLut); 00781 newLut->Delete(); 00782 00783 vtkLookupTable* newLutTwo = vtkLookupTable::New(); 00784 newLutTwo->DeepCopy (realLut); 00785 newLutTwo->SetRange (v_min, v_max); 00786 this->WindowLevelTwo->SetLookupTable (newLutTwo); 00787 newLutTwo->Delete(); 00788 00789 } 00790 00791 00792 void Checkerboard::SetOrientation(unsigned int p_orientation) 00793 { 00794 if( (p_orientation > vtkViewImage::NB_PLAN_IDS - 1) || (this->Orientation == p_orientation) ) 00795 { 00796 return; 00797 } 00798 00799 this->Orientation = p_orientation; 00800 00801 00802 // setup the OrientationMatrix and the ScreenToRealWorldMatrix. Then, we have no 00803 // need to check the view's orientation to determine what slice to display: a 00804 // simple matrix multiplication will tell it for us. 00805 this->OrientationMatrix->Zero(); 00806 this->ScreenToRealWorldMatrix->Zero(); 00807 00808 00809 if( this->Orientation == vtkViewImage::SAGITTAL_ID ) 00810 { 00811 this->ImageReslice->SetResliceAxesDirectionCosines( 0, -1, 0, 00812 0, 0, 1, 00813 1, 0, 0); 00814 this->ImageResliceTwo->SetResliceAxesDirectionCosines( 0, -1, 0, 00815 0, 0, 1, 00816 1, 0, 0); 00817 this->OrientationMatrix->SetElement (0, 2, 0.0); 00818 this->OrientationMatrix->SetElement (1, 0, -1.0); 00819 this->OrientationMatrix->SetElement (2, 1, 1.0); 00820 00821 this->ScreenToRealWorldMatrix->SetElement (0, 0, 1.0); 00822 } 00823 00824 00825 if( this->Orientation == vtkViewImage::CORONAL_ID ) 00826 { 00827 if( this->Conventions == RADIOLOGIC ) 00828 { 00829 this->OrientationMatrix->SetElement(0, 0, 1.0); 00830 this->ImageReslice->SetResliceAxesDirectionCosines(1, 0, 0, 00831 0, 0, 1, 00832 0, 1, 0); 00833 this->ImageResliceTwo->SetResliceAxesDirectionCosines(1, 0, 0, 00834 0, 0, 1, 00835 0, 1, 0); 00836 } 00837 else 00838 { 00839 this->OrientationMatrix->SetElement(0, 0, -1.0); 00840 this->ImageReslice->SetResliceAxesDirectionCosines(-1, 0, 0, 00841 0, 0, 1, 00842 0, 1, 0); 00843 this->ImageResliceTwo->SetResliceAxesDirectionCosines(-1, 0, 0, 00844 0, 0, 1, 00845 0, 1, 0); 00846 } 00847 00848 this->OrientationMatrix->SetElement(2, 1, 1.0); 00849 this->ScreenToRealWorldMatrix->SetElement (1, 1, 1.0); 00850 } 00851 00852 00853 if( this->Orientation == vtkViewImage::AXIAL_ID ) 00854 { 00855 00856 00857 if( this->Conventions == RADIOLOGIC ) 00858 { 00859 this->OrientationMatrix->SetElement(0, 0, 1.0 ); 00860 this->ImageReslice->SetResliceAxesDirectionCosines(1, 0, 0, 00861 0, 1, 0, 00862 0, 0, 1); 00863 this->ImageResliceTwo->SetResliceAxesDirectionCosines(1, 0, 0, 00864 0, 1, 0, 00865 0, 0, 1); 00866 } 00867 else 00868 { 00869 this->OrientationMatrix->SetElement(0, 0, -1.0 ); 00870 this->ImageReslice->SetResliceAxesDirectionCosines(-1, 0, 0, 00871 0, 1, 0, 00872 0, 0, 1); 00873 this->ImageResliceTwo->SetResliceAxesDirectionCosines(-1, 0, 0, 00874 0, 1, 0, 00875 0, 0, 1); 00876 } 00877 00878 this->OrientationMatrix->SetElement(1, 1, 1.0 ); 00879 this->ScreenToRealWorldMatrix->SetElement (2, 2, 1.0); 00880 } 00881 00882 unsigned int direction = this->GetOrthogonalAxis (this->GetOrientation()); 00883 switch(direction) 00884 { 00885 case X_ID : 00886 this->DataSetCutPlane->SetNormal (1,0,0); 00887 break; 00888 case Y_ID : 00889 this->DataSetCutPlane->SetNormal (0,1,0); 00890 break; 00891 case Z_ID : 00892 this->DataSetCutPlane->SetNormal (0,0,1); 00893 break; 00894 } 00895 00896 //this->ImageReslice->Modified(); 00897 00898 this->UpdateImageActor(); // make sure update extent are up to date 00899 this->UpdatePosition(); // make sure reslicer origin are ok 00900 this->InitializeImagePositionAndSize(); // reset and center the view 00901 this->SetupAnnotations(); // make sure annotations are ok 00902 00903 this->Modified(); 00904 00905 } 00906 00907 00908 00909 vtkActor* Checkerboard::AddDataSet (vtkDataSet* dataset, vtkProperty* property) 00910 { 00911 00912 bool doit = true; 00913 00914 if (!dataset) 00915 doit = false; 00916 00917 if( this->HasDataSet (dataset) ) 00918 { 00919 doit = false; 00920 } 00921 vtkImageData* imagedata = NULL; 00922 imagedata = vtkImageData::SafeDownCast(dataset); 00923 00924 if (imagedata) 00925 { 00926 this->SetImage(imagedata); 00927 } 00928 else 00929 { 00930 00931 if ( !this->GetImage() ) 00932 { 00933 doit = false; 00934 } 00935 // don't constrain the memory of input datasets anymore. 00946 if (doit) 00947 { 00948 00949 vtkMatrix4x4* matrix = vtkMatrix4x4::New(); 00950 for (unsigned int i=0; i<3; i++) 00951 { 00952 for (unsigned int j=0; j<3; j++) 00953 { 00954 matrix->SetElement(i,j,this->ImageReslice->GetResliceAxes()->GetElement(j,i)); 00955 } 00956 matrix->SetElement(i,3,0); 00957 } 00958 matrix->SetElement(3,3,1); 00959 00960 vtkCutter* cutter = vtkCutter::New(); 00961 cutter->SetCutFunction (this->DataSetCutPlane); 00962 00963 // Very strangely in some cases (ex : landmarks) 00964 // the cutter increments the RefCount of the input dataset by 2 00965 // making some memory leek... 00966 // I could not manage to know what is wrong here 00967 00968 cutter->SetInput (dataset); 00969 cutter->Update(); 00970 00971 if (!cutter->GetOutput()) 00972 { 00973 vtkWarningMacro(<< "Unable to cut this dataset..."); 00974 matrix->Delete(); 00975 cutter->Delete(); 00976 return NULL; 00977 } 00978 00979 00980 vtkPolyDataMapper* mapper = vtkPolyDataMapper::New(); 00981 mapper->SetInput (cutter->GetOutput()); 00982 00983 vtkActor* actor = vtkActor::New(); 00984 actor->SetUserMatrix (matrix); 00985 actor->SetMapper (mapper); 00986 if (property) 00987 { 00988 actor->SetProperty (property); 00989 } 00990 00991 actor->PickableOff(); 00992 00993 this->AddActor (actor); 00994 this->DataSetList.push_back (dataset); 00995 this->DataSetActorList.push_back (actor); 00996 00997 this->ResetAndRestablishZoomAndCamera(); 00998 00999 actor->Delete(); 01000 mapper->Delete(); 01001 matrix->Delete(); 01002 cutter->Delete(); 01003 } 01004 } 01005 01006 01007 return this->GetDataSetActor(dataset); 01008 01009 } 01010 01011 01017 vtkActor* Checkerboard::SyncAddPolyData (vtkPolyData* polydata, vtkProperty* property, double thickness) 01018 { 01019 01020 if( this->IsLocked() ) 01021 { 01022 return NULL; 01023 } 01024 01025 01026 vtkActor* actor = this->AddPolyData (polydata, property, thickness); 01027 01028 this->Lock(); 01029 for( unsigned int i=0; i<this->Children.size(); i++) 01030 { 01031 // Checkerboard* view = dynamic_cast<Checkerboard*> (this->Children[i]); 01032 Checkerboard* view = Checkerboard::SafeDownCast (this->Children[i]); 01033 if( view ) 01034 { 01035 view->SyncAddPolyData (polydata, property, thickness); 01036 } 01037 } 01038 this->UnLock(); 01039 01040 return actor; 01041 01042 01043 } 01044 01045