diff --git a/src/src/Rendering/infinitiViewer.cxx b/src/src/Rendering/infinitiViewer.cxx index 6bb5253..9470604 100644 --- a/src/src/Rendering/infinitiViewer.cxx +++ b/src/src/Rendering/infinitiViewer.cxx @@ -1,630 +1,519 @@ #include "infinitiViewer.h" -#include "vtkCamera.h" -#include "vtkCommand.h" -#include "vtkImageData.h" -#include "vtkInformation.h" -#include "Interaction/ActorDraggableInteractorStyle.h" -#include "vtkObjectFactory.h" -#include "vtkRenderWindow.h" -#include "vtkRenderWindowInteractor.h" -#include "vtkRenderer.h" -#include "vtkStreamingDemandDrivenPipeline.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include "vtkImageSliceMapper.h" -#include "vtkLookupTable.h" -#include "vtkScalarBarActor.h" +#include +#include +#include #include -#include "vtkPiecewiseFunction.h" -#include "vector" -#include "vtkCornerAnnotation.h" +#include +#include +#include +#include + #include "Rendering/Measure/MeasureStore.h" -#include "vtkTextActor.h" -#include "vtkTextProperty.h" #include "IO/General/ColorMapReader.h" -#include "vtkMath.h" -#include "vtkImageStack.h" +#include "Interaction/ActorDraggableInteractorStyle.h" - -#include "IO/DICOM/DicomLoader.h" - vtkStandardNewMacro(infinitiViewer); -bool simpleFusionableCheck(vtkImageData* a, vtkImageData* b) -{ - double* origin1 = a->GetOrigin(); - double* origin2 = b->GetOrigin(); - return (origin1[0] == origin2[0]) && (origin1[1] == origin2[1]) && (origin1[2] == origin2[2]); -} - -void infinitiViewer::SetFusionInputData(vtkImageData* data) -{ - if (!this->GetInput()) return; - if (!simpleFusionableCheck(data, this->GetInput())) return; - if (!this->FusionMapper) { - auto m = vtkImageSliceMapper::New(); -// m->SetBaseImageMapper(ImageMapper); - this->FusionMapper = m; - this->FusionMapper->SliceAtFocalPointOn(); - this->FusionMapper->SliceFacesCameraOn(); - - FusionMapper->SetInputData(data); - this->FusionActor = vtkImageSlice::New(); - //must set fusion image slice layer to 1 to make main image is active layer of image stack - FusionActor->GetProperty()->SetLayerNumber(1); - FusionActor->SetPickable(false); - FusionActor->SetMapper(FusionMapper); - } - else if (data == FusionMapper->GetInput()) return; - const auto prop = FusionActor->GetProperty(); - if (firstFusion) { - vtkNew table; - table->SetHueRange(1.0, 0.0); - table->SetSaturationRange(0.5, 1.0); - table->SetValueRange(0.0, 1.0); - table->SetAboveRangeColor(0.0, 0.0, 0.0, 0.0); - table->SetBelowRangeColor(0.0, 0.0, 0.0, 0.0); - table->SetNumberOfColors(512); - table->UseAboveRangeColorOn(); - table->UseBelowRangeColorOn(); - table->SetAlpha(FusionOpacity); - table->Build(); - prop->SetLookupTable(table); - firstFusion = false; - } -#ifdef IN_TEST_MODE - //vtkTextProperty* vtkTextProperty = vtkTextProperty::New(); - vtkNew LabelTextProperty; - LabelTextProperty->SetFontSize(16); - LabelTextProperty->SetBold(1); - LabelTextProperty->SetItalic(1); - LabelTextProperty->SetShadow(1); - LabelTextProperty->SetFontFamilyToArial(); - - - bar = vtkScalarBarActor::New(); - bar->GetPositionCoordinate()->SetCoordinateSystemToNormalizedViewport(); - bar->SetLookupTable(prop->GetLookupTable()); - bar->SetWidth(0.1); - bar->SetHeight(0.4); - bar->SetPosition(0.04, 0.4); - //bar->DrawFrameOn(); - bar->SetMaximumHeightInPixels(250); - bar->SetMaximumWidthInPixels(50); - - bar->SetNumberOfLabels(2); - bar->SetLabelFormat("%.0f"); - - bar->UnconstrainedFontSizeOff(); - bar->SetUnconstrainedFontSize(true); - bar->SetLabelTextProperty(LabelTextProperty); - this->Renderer->AddActor(bar); - - - OpacityActor = vtkTextActor::New(); - //OpacityActor->SetInput("50%"); - OpacityActor->GetPositionCoordinate()->SetCoordinateSystemToNormalizedViewport(); - OpacityActor->SetPosition(0.04, 0.35); - OpacityActor->SetTextProperty(LabelTextProperty); - SetScalarBarTitle(FusionOpacity); - - - - - this->Renderer->AddActor(OpacityActor); -#endif - -} - -void infinitiViewer::SetFusionColorLeveL(double level) -{ - if (FusionActor) - { - FusionActor->GetProperty()->SetColorLevel(level); - PrepareFusionColorTable(FusionActor->GetProperty()->GetLookupTable()); - } -} - -void infinitiViewer::SetFusionColorWindow(double window) -{ - if (FusionActor) - { - FusionActor->GetProperty()->SetColorWindow(window); - PrepareFusionColorTable(FusionActor->GetProperty()->GetLookupTable()); - } -} -void infinitiViewer::SetScalarBarTitle(double FusionOpa) -{ - int opa = int(FusionOpa * 100); - std::string str_opa = std::to_string(opa); - str_opa.append("%"); - OpacityActor->SetInput(str_opa.c_str()); -} - -void infinitiViewer::IncreFusionOpacity(double percent) -{ - if (FusionActor) { - FusionOpacity += percent; - FusionOpacity = FusionOpacity > 1.0 ? 1.0 : FusionOpacity; - FusionOpacity = FusionOpacity < 0.0 ? 0.0 : FusionOpacity; - SetScalarBarTitle(FusionOpacity); - FusionActor->GetProperty()->GetLookupTable()->SetAlpha(FusionOpacity); - PrepareFusionColorTable(FusionActor->GetProperty()->GetLookupTable()); - } -} - -void infinitiViewer::SetFusionOpacity(double opacity) -{ - if (FusionActor) { - opacity = opacity > 1.0 ? 1.0 : opacity; - opacity = opacity < 0.0 ? 0.0 : opacity; - FusionOpacity = opacity; - SetScalarBarTitle(FusionOpacity); - FusionActor->GetProperty()->GetLookupTable()->SetAlpha(FusionOpacity); - PrepareFusionColorTable(FusionActor->GetProperty()->GetLookupTable()); - } -} - -void prepareLookTable(vtkLookupTable* table) -{ - table->SetAboveRangeColor(0.0, 0.0, 0.0, 0.0); - table->SetBelowRangeColor(0.0, 0.0, 0.0, 0.0); - table->UseAboveRangeColorOn(); - table->UseBelowRangeColorOn(); -} - -void prepareTransferFunction(vtkDiscretizableColorTransferFunction* table, vtkImageProperty* prop, const std::vector>& vector) -{ - - double min = prop->GetColorLevel() - prop->GetColorWindow() * 0.5; - double max = prop->GetColorLevel() + prop->GetColorWindow() * 0.5; - int size = table->GetSize(); - - table->RemoveAllPoints(); - for (int i = 0; i < size; i++) - { - table->AddRGBPoint(min + vector[i][0] * prop->GetColorWindow(), - vector[i][1], vector[i][2], vector[i][3], vector[i][4], vector[i][5]); - } - vtkNew< vtkPiecewiseFunction> wise; - wise->AddPoint(min - 0.05, 0.0); - wise->AddPoint(min, table->GetAlpha()); - wise->AddPoint(max, table->GetAlpha()); - //wise->AddPoint(max + 0.05, 0.0); - wise->ClampingOn(); //Default is On - table->SetScalarOpacityFunction(wise); - table->EnableOpacityMappingOn(); -} - - -void infinitiViewer::SetFusionColorTable(vtkScalarsToColors* table) -{ - if (!FusionActor) return; - PrepareFusionColorTable(table, true); - FusionActor->GetProperty()->SetLookupTable(table); -#ifdef IN_TEST_MODE - bar->SetLookupTable(table); -#endif -} - -void infinitiViewer::SetFusionColorPreset(const char* preset) -{ - auto values = ColorMapReader::DefaultPresets()->GetPresetValues(preset); - auto PresetType = ColorMapReader::DefaultPresets()->GetPresetType(preset); - - switch (PresetType) { - case ColorMapReader::RGBPoints: - { - vtkNew< vtkDiscretizableColorTransferFunction> table; - for (int i = 0; i + 3 < values.size(); i += 4) { - table->AddRGBPoint(values[i], values[i + 1], values[i + 2], values[i + 3]); - } - double* nancolor = ColorMapReader::DefaultPresets()->GetPresetNanColor(preset); - if (nancolor) - { - table->SetNanColor(nancolor); - } - this->SetFusionColorTable(table); - break; - } - case ColorMapReader::IndexedColors: { - vtkNew< vtkDiscretizableColorTransferFunction> table; - for (int i = 0; i + 2 < values.size() - 1; i += 2) { - table->AddRGBPoint(((double)i) / ((double)(values.size() - 3)), values[i], values[i + 1], - values[i + 2], 1.0, 1.0); - table->AddRGBPoint(1.0, values[values.size() - 3], values[values.size() - 2], - values[values.size() - 1]); - double* nancolor = ColorMapReader::DefaultPresets()->GetPresetNanColor(preset); - if (nancolor) { - table->SetNanColor(nancolor); - } - this->SetFusionColorTable(table); - break; - } - } - default: - break; - } -} - -void infinitiViewer::PrepareFusionColorTable(vtkScalarsToColors* table, bool reset) -{ - const auto prop = FusionActor->GetProperty(); - table->SetAlpha(FusionOpacity); - if (table->IsA("vtkLookupTable")) { - auto t = vtkLookupTable::SafeDownCast(table); - if (!t) return; - prepareLookTable(t); - } - else if (table->IsA("vtkDiscretizableColorTransferFunction")) - { - auto t = vtkDiscretizableColorTransferFunction::SafeDownCast(table); - if (!t) return; - if (reset) - { - int size = t->GetSize(); - fusion_tf_vector.clear(); - for (int i = 0; i < size; i++) - { - double v[6] = { 0,0,0,0,0,0 }; - t->GetNodeValue(i, v); - std::vector nt = { v[0],v[1],v[2],v[3],v[4],v[5] }; - fusion_tf_vector.push_back(nt); - } - } - prepareTransferFunction(t, prop, fusion_tf_vector); - } - table->Build(); -} - -void infinitiViewer::RemoveFusionActor() -{ - this->Renderer->RemoveActor(bar); - bar->Delete(); - bar = nullptr; - this->Renderer->RemoveActor(OpacityActor); - OpacityActor->Delete(); - OpacityActor = nullptr; -} -void infinitiViewer::RemoveFusionData() -{ - if (!FusionMapper) return; - if (ImageStack->HasImage(FusionActor)) { - ImageStack->RemoveImage(FusionActor); - } - FusionMapper->Delete(); - FusionMapper = nullptr; - FusionActor->Delete(); - FusionActor = nullptr; - //reset first fusion flag - firstFusion = true; - - RemoveFusionActor(); - //this->Render(); -} - -//---------------------------------------------------------------------------- +//----------------------------------------------------------------------------- infinitiViewer::infinitiViewer() -{ - this->RenderWindow = nullptr; - this->Renderer = nullptr; - this->ImageStack = vtkImageStack::New(); - this->ImageActor = vtkImageSlice::New(); - this->ImageMapper = vtkImageSliceMapper::New(); - this->ImageMapper->SliceAtFocalPointOn(); - this->ImageMapper->SliceFacesCameraOn(); + : vtkObject(), + RenderWindow(nullptr), Renderer(nullptr), ImageStack(vtkImageStack::New()), + ImageActor(vtkImageSlice::New()), ImageMapper(vtkImageSliceMapper::New()), FusionActor(nullptr), + FusionMapper(nullptr), Interactor(nullptr), InteractorStyle(nullptr), OpacityActor(nullptr), + cornerAnnotation(vtkCornerAnnotation::New()), bar(nullptr), + SliceOrientation(infinitiViewer::SLICE_ORIENTATION_XY), FirstRender(1), Slice(0), loadedMeasureSlice(0), + currentPresetIndex(1), Fusion(false), firstFusion(true), FusionOpacity(0.5), list(nullptr), + measureStore(MeasureStore::Instance()), + rulerActive(false) { + this->ImageMapper->SliceAtFocalPointOn(); + this->ImageMapper->SliceFacesCameraOn(); this->ImageActor->SetPickable(true); - this->ImageActor->SetMapper(this->ImageMapper); + this->ImageActor->SetMapper(this->ImageMapper); ImageStack->AddImage(ImageActor); - this->FusionActor = nullptr; - this->FusionMapper = nullptr; - this->Interactor = nullptr; - this->InteractorStyle = nullptr; + + vtkNew prop; + prop->SetFontFamilyToArial(); + prop->ShadowOn(); + this->cornerAnnotation->SetTextProperty(prop); + this->cornerAnnotation->GetTextProperty()->SetColor(1, 1, 0.5); + // Annotate the image with window/level and mouse over pixel information + cornerAnnotation->SetLinearFontScaleFactor(2); + cornerAnnotation->SetNonlinearFontScaleFactor(1); + cornerAnnotation->SetMaximumFontSize(FontSizeHelper::font_size); + + vtkRenderWindow *renwin = vtkRenderWindow::New(); + infinitiViewer::SetRenderWindow(renwin); + renwin->Delete(); - this->cornerAnnotation = vtkCornerAnnotation::New(); - vtkNew prop; - prop->SetFontFamilyToArial(); - prop->ShadowOn(); - this->cornerAnnotation->SetTextProperty(prop); - this->cornerAnnotation->GetTextProperty()->SetColor(1, 1, 0.5); - // Annotate the image with window/level and mouse over pixel information - cornerAnnotation->SetLinearFontScaleFactor(2); - cornerAnnotation->SetNonlinearFontScaleFactor(1); - cornerAnnotation->SetMaximumFontSize(FontSizeHelper::font_size); - - OpacityActor = nullptr; - bar = nullptr; - loadedMeasureSlice = 0; - - - this->Slice = 0; - this->FirstRender = 1; - this->SliceOrientation = infinitiViewer::SLICE_ORIENTATION_XY; - - // measureStore = new MeasureStore; - measureStore = MeasureStore::Instance(); - // Setup the pipeline - - vtkRenderWindow* renwin = vtkRenderWindow::New(); - infinitiViewer::SetRenderWindow(renwin); - renwin->Delete(); - - - vtkRenderer* ren = vtkRenderer::New(); + vtkRenderer *ren = vtkRenderer::New(); infinitiViewer::SetRenderer(ren); - ren->Delete(); + ren->Delete(); infinitiViewer::InstallPipeline(); - uintptr_t handler = reinterpret_cast(this); - sprintf(SOP_UID, "%llu", handler); + uintptr_t handler = reinterpret_cast(this); + sprintf(SOP_UID, "%llu", handler); } -//---------------------------------------------------------------------------- -infinitiViewer::~infinitiViewer() -{ - if (this->ImageMapper) - { - this->ImageMapper->SetInputData(nullptr); - this->ImageMapper->Delete(); - this->ImageMapper = nullptr; - } - if (this->ImageActor) - { - this->ImageActor->Delete(); - this->ImageActor = nullptr; - } - - if (this->FusionMapper) - { - this->FusionMapper->Delete(); - this->FusionMapper = nullptr; - } - if (this->FusionActor) - { - this->FusionActor->Delete(); - this->FusionActor = nullptr; - } - - if (this->Renderer) - { - this->Renderer->Delete(); - this->Renderer = nullptr; - } - - if (this->RenderWindow) - { - this->RenderWindow->Delete(); - this->RenderWindow = nullptr; - } - - if (this->Interactor) - { - this->Interactor->Delete(); - this->Interactor = nullptr; - } - - if (this->InteractorStyle) - { - this->InteractorStyle->SetCornerAnnotation(nullptr); - this->InteractorStyle->Delete(); - this->InteractorStyle = nullptr; - } - if (this->cornerAnnotation) { - this->cornerAnnotation->Delete(); - this->cornerAnnotation = nullptr; - } - measureStore->RemoveAllInSeries(SOP_UID); - // measureStore->Clear(); - //delete measureStore; -} - -//---------------------------------------------------------------------------- -void infinitiViewer::SetupInteractor(vtkRenderWindowInteractor* arg) -{ - if (this->Interactor == arg) - { - return; - } - - this->UnInstallPipeline(); - - if (this->Interactor) - { - this->Interactor->UnRegister(this); - } - - this->Interactor = arg; - - if (this->Interactor) - { - this->Interactor->Register(this); - } - - this->InstallPipeline(); - - if (this->Renderer) - { - this->Renderer->GetActiveCamera()->ParallelProjectionOn(); - } -} - -//---------------------------------------------------------------------------- -void infinitiViewer::SetRenderWindow(vtkRenderWindow* arg) -{ - if (this->RenderWindow == arg) - { - return; - } - - this->UnInstallPipeline(); - - if (this->RenderWindow) - { - this->RenderWindow->UnRegister(this); - } - - this->RenderWindow = arg; - - if (this->RenderWindow) - { - this->RenderWindow->Register(this); - } - this->RenderWindow->AddObserver(vtkCommand::EventIds::RenderEvent, this, &infinitiViewer::RenderRuler); - this->InstallPipeline(); -} - -//---------------------------------------------------------------------------- -void infinitiViewer::SetRenderer(vtkRenderer* arg) -{ - if (this->Renderer == arg) - { - return; - } - - this->UnInstallPipeline(); - - if (this->Renderer) - { - this->Renderer->UnRegister(this); - } - - this->Renderer = arg; - - if (this->Renderer) - { - this->Renderer->Register(this); - } - - this->InstallPipeline(); - this->UpdateOrientation(); -} - -//---------------------------------------------------------------------------- -void infinitiViewer::SetSize(int width, int height) -{ - this->RenderWindow->SetSize(width, height); -} - -//---------------------------------------------------------------------------- -int* infinitiViewer::GetSize() -{ - return this->RenderWindow->GetSize(); -} - -//---------------------------------------------------------------------------- -void infinitiViewer::GetSliceRange(int& min, int& max) -{ - vtkAlgorithm* input = this->GetInputAlgorithm(); - if (input) - { - input->UpdateInformation(); - int* w_ext = - input->GetOutputInformation(0)->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()); - min = w_ext[this->SliceOrientation * 2]; - max = w_ext[this->SliceOrientation * 2 + 1]; - } -} - -//---------------------------------------------------------------------------- -int* infinitiViewer::GetSliceRange() -{ - vtkAlgorithm* input = this->GetInputAlgorithm(); - if (input) - { - input->UpdateInformation(); - return input->GetOutputInformation(0)->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()) + - this->SliceOrientation * 2; - } - return nullptr; -} - -//---------------------------------------------------------------------------- -int infinitiViewer::GetSliceMin() -{ - int* range = this->GetSliceRange(); - if (range) - { - return range[0]; - } - return 0; -} - -//---------------------------------------------------------------------------- -int infinitiViewer::GetSliceMax() -{ - int* range = this->GetSliceRange(); - if (range) - { - return range[1]; - } - return 0; -} - -//---------------------------------------------------------------------------- -void infinitiViewer::SetSlice(int slice) -{ - int* range = this->GetSliceRange(); - if (range) - { - if (slice < range[0]) - { - slice = range[0]; - } - else if (slice > range[1]) - { - slice = range[1]; - } - } - - int lastSliceNumber = this->ImageMapper->GetSliceNumber(); - if (lastSliceNumber == slice) - { - return; - } - - this->Slice = slice; - this->Modified(); - //this->ImageMapper->SetSliceNumber(slice); - vtkCamera* camera = this->Renderer->GetActiveCamera(); - vtkAlgorithm* input = this->GetInputAlgorithm(); - if (!input || !this->ImageActor) - { - return; - } - - input->UpdateInformation(); - vtkInformation* outInfo = input->GetOutputInformation(0); - double* spacing = outInfo->Get(vtkDataObject::SPACING()); - double* origin = outInfo->Get(vtkDataObject::ORIGIN()); - double* pos = camera->GetPosition(); - - double npv = origin[this->SliceOrientation] + this->Slice * spacing[this->SliceOrientation]; - camera->SetDistance(fabs(npv - pos[this->SliceOrientation])); - if (Fusion && FusionMapper){ - FusionMapper->SetClippingPlanes(ImageMapper->GetClippingPlanes()); +//----------------------------------------------------------------------------- +infinitiViewer::~infinitiViewer() { + if (this->ImageMapper) { + this->ImageMapper->SetInputData(nullptr); + this->ImageMapper->Delete(); + this->ImageMapper = nullptr; + } + if (this->ImageActor) { + this->ImageActor->Delete(); + this->ImageActor = nullptr; } - this->Render(); - if (InteractorStyle) - InteractorStyle->InvokeEvent(ActorDraggableInteractorStyle::SlicedEvent, &this->Slice); + if (this->FusionMapper) { + this->FusionMapper->Delete(); + this->FusionMapper = nullptr; + } + if (this->FusionActor) { + this->FusionActor->Delete(); + this->FusionActor = nullptr; + } + + if (this->Renderer) { + this->Renderer->Delete(); + this->Renderer = nullptr; + } + + if (this->RenderWindow) { + this->RenderWindow->Delete(); + this->RenderWindow = nullptr; + } + + if (this->Interactor) { + this->Interactor->Delete(); + this->Interactor = nullptr; + } + + if (this->InteractorStyle) { + this->InteractorStyle->SetCornerAnnotation(nullptr); + this->InteractorStyle->Delete(); + this->InteractorStyle = nullptr; + } + if (this->cornerAnnotation) { + this->cornerAnnotation->Delete(); + this->cornerAnnotation = nullptr; + } + measureStore->RemoveAllInSeries(SOP_UID); + // measureStore->Clear(); + //delete measureStore; +} + +void infinitiViewer::SetupImageViewer() { + this->SetColorLevel(m_cornerInfo.win_level); + this->SetColorWindow(m_cornerInfo.win_width); + //this->GetRenderer()->ResetCamera(); + this->SetSliceOrientationToXY(); + this->Render(); //first render will call resetcamera + this->SetSlice(0); + UpdateCornerInfoAll(); +} + +// Render Pipe line------------------------------------------------------------ +vtkImageData *infinitiViewer::GetInput() { + return this->ImageMapper->GetInput(); +} + +vtkInformation *infinitiViewer::GetInputInformation() { + return this->ImageMapper->GetInputInformation(); +} + +vtkAlgorithm *infinitiViewer::GetInputAlgorithm() { + return this->ImageMapper->GetInputAlgorithm(); +} + +void infinitiViewer::SetupInteractor(vtkRenderWindowInteractor *arg) { + if (this->Interactor == arg) { + return; + } + + this->UnInstallPipeline(); + + if (this->Interactor) { + this->Interactor->UnRegister(this); + } + + this->Interactor = arg; + + if (this->Interactor) { + this->Interactor->Register(this); + } + + this->InstallPipeline(); + + if (this->Renderer) { + this->Renderer->GetActiveCamera()->ParallelProjectionOn(); + } +} + +void infinitiViewer::SetRenderWindow(vtkRenderWindow *arg) { + if (this->RenderWindow == arg) { + return; + } + + this->UnInstallPipeline(); + + if (this->RenderWindow) { + this->RenderWindow->UnRegister(this); + } + + this->RenderWindow = arg; + + if (this->RenderWindow) { + this->RenderWindow->Register(this); + } + this->RenderWindow->AddObserver(vtkCommand::EventIds::RenderEvent, this, &infinitiViewer::RenderRuler); + this->InstallPipeline(); +} + +void infinitiViewer::SetRenderer(vtkRenderer *arg) { + if (this->Renderer == arg) { + return; + } + + this->UnInstallPipeline(); + + if (this->Renderer) { + this->Renderer->UnRegister(this); + } + + this->Renderer = arg; + + if (this->Renderer) { + this->Renderer->Register(this); + } + + this->InstallPipeline(); + this->UpdateOrientation(); +} + +void infinitiViewer::SetInputData(vtkImageData *in) { +#ifdef _DEBUG + printf("fusion imageDataOrigin:%f,%f,%f", in->GetOrigin()[0], in->GetOrigin()[1], in->GetOrigin()[2]); + printf("fusion spacing:%f,%f,%f", in->GetSpacing()[0], in->GetSpacing()[1], in->GetSpacing()[2]); +#endif + this->FirstRender = 1; + this->ImageActor->GetMapper()->SetInputData(in); + this->RemoveFusionData(); + this->ActiveRuler(); + // this->UpdateDisplayExtent(); +} + +void infinitiViewer::SetInputConnection(vtkAlgorithmOutput *input) { + this->ImageMapper->SetInputConnection(input); + this->RemoveFusionData(); +} + +vtkTypeBool infinitiViewer::GetOffScreenRendering() { + return this->RenderWindow->GetOffScreenRendering(); +} + +void infinitiViewer::SetOffScreenRendering(vtkTypeBool i) { + this->RenderWindow->SetOffScreenRendering(i); +} + +void infinitiViewer::InstallPipeline() { + if (this->RenderWindow && this->Renderer) { + this->RenderWindow->AddRenderer(this->Renderer); + } + + if (this->Interactor) { + if (!this->InteractorStyle) { + this->InteractorStyle = ActorDraggableInteractorStyle::New(); + this->InteractorStyle->SetInteractionModeToImageSlicing(); + this->InteractorStyle->SetCurrentImageNumber(0); + this->InteractorStyle->SetCornerAnnotation(cornerAnnotation); + + this->InteractorStyle->AddObserver(ActorDraggableInteractorStyle::DraggableStyleEvents::EndMeasureEvent, + this, &infinitiViewer::AddMeasures); + this->InteractorStyle->AddObserver(ActorDraggableInteractorStyle::DraggableStyleEvents::DeleteMeasureEvent, + this, &infinitiViewer::RemoveMeasures); + this->InteractorStyle->AddObserver(ActorDraggableInteractorStyle::DraggableStyleEvents::SliceEvent, this, + &infinitiViewer::ChangeSlice); + this->InteractorStyle->AddObserver(ActorDraggableInteractorStyle::DraggableStyleEvents::SlicedEvent, this, + &infinitiViewer::LoadMeasures); + InteractorStyle->AddObserver(ActorDraggableInteractorStyle::SlicedEvent, this, + &infinitiViewer::UpdateTopLeftCornerInfo); + + //for convert vtkEvent to Qt signal + this->InteractorStyle->AddObserver(ActorDraggableInteractorStyle::DraggableStyleEvents::SlicedEvent, this, + &infinitiViewer::raiseEvent); + this->InteractorStyle->AddObserver(ActorDraggableInteractorStyle::DraggableStyleEvents::EndDollyEvent, this, + &infinitiViewer::raiseEvent); + this->InteractorStyle->AddObserver(vtkCommand::EventIds::EndWindowLevelEvent, this, + &infinitiViewer::raiseEvent); + this->InteractorStyle->AddObserver(vtkCommand::EventIds::EndPanEvent, this, &infinitiViewer::raiseEvent); + } + + this->Interactor->SetInteractorStyle(this->InteractorStyle); + this->Interactor->SetRenderWindow(this->RenderWindow); + } + + if (this->Renderer && this->ImageActor) { + this->Renderer->AddViewProp(this->ImageStack); +// this->Renderer->AddViewProp(this->ImageActor); + this->Renderer->GetActiveCamera()->SetParallelProjection(1); + this->Renderer->SetBackground(0.0, 0.0, 0.0); + } + if (this->Renderer && this->FusionActor && Fusion) { + this->ImageStack->AddImage(this->FusionActor); + } + if (this->Renderer && this->cornerAnnotation) { + this->Renderer->AddViewProp(cornerAnnotation); + } + loadedMeasureSlice = -1; +} + +void infinitiViewer::UnInstallPipeline() { + if (this->ImageActor && this->ImageMapper) { + // this->ImageActor->SetMapper(nullptr); + } + if (this->Renderer && this->FusionActor && this->Renderer->HasViewProp(FusionActor)) { + this->Renderer->RemoveViewProp(this->FusionActor); + } + if (this->Renderer && this->ImageActor) { + this->Renderer->RemoveViewProp(this->ImageActor); + } + + if (this->RenderWindow && this->Renderer) { + this->RenderWindow->RemoveRenderer(this->Renderer); + } + + if (this->Interactor) { + this->Interactor->SetInteractorStyle(nullptr); + this->Interactor->SetRenderWindow(nullptr); + } +} + +void infinitiViewer::Render() { + if (this->FirstRender) { + // // Initialize the size if not set yet + + vtkAlgorithm *input = this->GetInputAlgorithm(); + if (input) { + input->UpdateInformation(); + int *w_ext = + this->GetInputInformation()->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()); + int xs = 0, ys = 0; + + switch (this->SliceOrientation) { + case infinitiViewer::SLICE_ORIENTATION_XY: + default: + xs = w_ext[1] - w_ext[0] + 1; + ys = w_ext[3] - w_ext[2] + 1; + break; + + case infinitiViewer::SLICE_ORIENTATION_XZ: + xs = w_ext[1] - w_ext[0] + 1; + ys = w_ext[5] - w_ext[4] + 1; + break; + + case infinitiViewer::SLICE_ORIENTATION_YZ: + xs = w_ext[3] - w_ext[2] + 1; + ys = w_ext[5] - w_ext[4] + 1; + break; + } + + // if it would be smaller than 150 by 100 then limit to 150 by 100 + if (this->RenderWindow->GetSize()[0] == 0) { + this->RenderWindow->SetSize(xs < 150 ? 150 : xs, ys < 100 ? 100 : ys); + } + + if (this->Renderer) { + this->Renderer->ResetCamera(); + auto camera = this->Renderer->GetActiveCamera(); + //camera 必须要动一下,直接loadfusion才能正常显示 + int lastIndex = ImageMapper->GetSliceNumber(); + //camera->GetPosition(cameraPosition); + double distance = camera->GetDistance(); + camera->SetDistance(distance - 0.005); + //camera->GetPosition(cameraPosition); + int currentIndex = ImageMapper->GetSliceNumber(); + if (currentIndex != lastIndex) this->SetSlice(lastIndex); + ResetZoomScaleToFitWindowSize(); +// this->Renderer->GetActiveCamera()->SetParallelScale(xs < 150 ? 75 : (xs - 1) / 2.0); + //calibration of image by VFlip + //this->Renderer->GetActiveCamera()->Elevation(-180); + //this->Renderer->GetActiveCamera()->Roll(180); + //this->Renderer->ResetCameraClippingRange(); + + } + this->FirstRender = 0; + } + } + if (this->GetInput()) { + if (Fusion && FusionActor && !this->ImageStack->HasImage(FusionActor)) { +// this->Renderer->AddActor(FusionActor); + + this->ImageStack->AddImage(FusionActor); + } + if (!Fusion && FusionActor && this->ImageStack->HasImage(FusionActor)) { +// this->Renderer->RemoveViewProp(FusionActor); + this->ImageStack->RemoveImage(FusionActor); + + } + this->LoadMeasures(); + this->RenderWindow->Render(); + } +} + +// slice about----------------------------------------------------------------- +void infinitiViewer::GetSliceRange(int &min, int &max) { + vtkAlgorithm *input = this->GetInputAlgorithm(); + if (input) { + input->UpdateInformation(); + int *w_ext = + input->GetOutputInformation(0)->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()); + min = w_ext[this->SliceOrientation * 2]; + max = w_ext[this->SliceOrientation * 2 + 1]; + } +} + +int *infinitiViewer::GetSliceRange() { + vtkAlgorithm *input = this->GetInputAlgorithm(); + if (input) { + input->UpdateInformation(); + return input->GetOutputInformation(0)->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()) + + this->SliceOrientation * 2; + } + return nullptr; +} + +int infinitiViewer::GetSliceMin() { + int *range = this->GetSliceRange(); + if (range) { + return range[0]; + } + return 0; +} + +int infinitiViewer::GetSliceMax() { + int *range = this->GetSliceRange(); + if (range) { + return range[1]; + } + return 0; } int infinitiViewer::GetSlice() { - return this->ImageMapper->GetSliceNumber(); + return this->ImageMapper->GetSliceNumber(); +} + +void infinitiViewer::SetSlice(int slice) { + int *range = this->GetSliceRange(); + if (range) { + if (slice < range[0]) { + slice = range[0]; + } else if (slice > range[1]) { + slice = range[1]; + } + } + + int lastSliceNumber = this->ImageMapper->GetSliceNumber(); + if (lastSliceNumber == slice) { + return; + } + + this->Slice = slice; + this->Modified(); + //this->ImageMapper->SetSliceNumber(slice); + vtkCamera *camera = this->Renderer->GetActiveCamera(); + vtkAlgorithm *input = this->GetInputAlgorithm(); + if (!input || !this->ImageActor) { + return; + } + + input->UpdateInformation(); + vtkInformation *outInfo = input->GetOutputInformation(0); + double *spacing = outInfo->Get(vtkDataObject::SPACING()); + double *origin = outInfo->Get(vtkDataObject::ORIGIN()); + double *pos = camera->GetPosition(); + + double npv = origin[this->SliceOrientation] + this->Slice * spacing[this->SliceOrientation]; + camera->SetDistance(fabs(npv - pos[this->SliceOrientation])); + if (Fusion && FusionMapper) { + FusionMapper->SetClippingPlanes(ImageMapper->GetClippingPlanes()); + } + + this->Render(); + if (InteractorStyle) + InteractorStyle->InvokeEvent(ActorDraggableInteractorStyle::SlicedEvent, &this->Slice); } void infinitiViewer::ChangeSlice(vtkObject *, unsigned long eventid, void *calldata) { int lastSlice = GetSlice(); - int* p = (int*)calldata; - int newSlice = lastSlice+(*p); - newSlice = newSlice<0?GetSliceMax():(newSlice>GetSliceMax()?0:newSlice); + int *p = (int *) calldata; + int newSlice = lastSlice + (*p); + newSlice = newSlice < 0 ? GetSliceMax() : (newSlice > GetSliceMax() ? 0 : newSlice); SetSlice(newSlice); } -void infinitiViewer::SyncSlicePoint(double * point) { +void infinitiViewer::GetSlicePoint(double *point) { + double focusPoint[4] = {.0, .0, .0, 1.0}; + Renderer->GetActiveCamera()->GetFocalPoint(focusPoint); + matrix->MultiplyPoint(focusPoint, focusPoint); + focusPoint[0] += imageDataOrigin[0]; + focusPoint[1] += imageDataOrigin[1]; + focusPoint[2] += imageDataOrigin[2]; + point[0] = focusPoint[0]; + point[1] = focusPoint[1]; + point[2] = focusPoint[2]; +} + +vtkSmartPointer infinitiViewer::GetSliceBoundPoints() { + double bounds[6] = {.0, .0, .0, .0, .0, .0}; + ImageMapper->GetBounds(bounds); + vtkCamera *camera = this->Renderer->GetActiveCamera(); + double fpt[3] = {.0, .0, .0}; + camera->GetFocalPoint(fpt); + bounds[SliceOrientation * 2] = fpt[SliceOrientation]; + vtkSmartPointer pts = vtkSmartPointer::New(); + //只取4个点 + pts->InsertNextPoint(bounds[0], bounds[2], bounds[4]); + if (SliceOrientation != 1) { + pts->InsertNextPoint(bounds[0], bounds[3], bounds[4]); + if (SliceOrientation != 2) { + pts->InsertNextPoint(bounds[0], bounds[3], bounds[5]); + pts->InsertNextPoint(bounds[0], bounds[2], bounds[5]); + } + } + if (SliceOrientation != 0) { + if (SliceOrientation != 1) { + pts->InsertNextPoint(bounds[1], bounds[3], bounds[4]); + pts->InsertNextPoint(bounds[1], bounds[2], bounds[4]); + } else { + pts->InsertNextPoint(bounds[1], bounds[2], bounds[4]); + pts->InsertNextPoint(bounds[1], bounds[2], bounds[5]); + pts->InsertNextPoint(bounds[0], bounds[2], bounds[5]); + } + } + return pts; +} + +void infinitiViewer::SyncSlicePoint(double *point) { double focusPoint[4] = {.0, .0, .0, 1.0}; focusPoint[0] = point[0] - imageDataOrigin[0]; focusPoint[1] = point[1] - imageDataOrigin[1]; @@ -640,571 +529,633 @@ void infinitiViewer::SyncSlicePoint(double * point) { Renderer->GetActiveCamera()->SetFocalPoint(f); } -void infinitiViewer::GetSlicePoint(double * point) { - double focusPoint[4] = {.0, .0, .0, 1.0}; - Renderer->GetActiveCamera()->GetFocalPoint(focusPoint); - matrix->MultiplyPoint(focusPoint, focusPoint); - focusPoint[0] += imageDataOrigin[0]; - focusPoint[1] += imageDataOrigin[1]; - focusPoint[2] += imageDataOrigin[2]; - point[0] = focusPoint[0]; - point[1] = focusPoint[1]; - point[2] = focusPoint[2]; -} - -vtkSmartPointer infinitiViewer::GetSliceBoundPoints(){ - double bounds[6] ={.0, .0, .0, .0, .0, .0}; - ImageMapper->GetBounds(bounds); - vtkCamera* camera = this->Renderer->GetActiveCamera(); - double fpt[3] = {.0, .0, .0}; - camera->GetFocalPoint(fpt); - bounds[SliceOrientation*2] = fpt[SliceOrientation]; - vtkSmartPointer pts = vtkSmartPointer::New(); - //只取4个点 - pts->InsertNextPoint(bounds[0],bounds[2],bounds[4]); - if (SliceOrientation!=1){ - pts->InsertNextPoint(bounds[0],bounds[3],bounds[4]); - if (SliceOrientation!=2) { - pts->InsertNextPoint(bounds[0], bounds[3], bounds[5]); - pts->InsertNextPoint(bounds[0], bounds[2], bounds[5]); - } - } - if (SliceOrientation!=0){ - if (SliceOrientation!=1){ - pts->InsertNextPoint(bounds[1],bounds[3],bounds[4]); - pts->InsertNextPoint(bounds[1],bounds[2],bounds[4]); - } - else{ - pts->InsertNextPoint(bounds[1],bounds[2],bounds[4]); - pts->InsertNextPoint(bounds[1],bounds[2],bounds[5]); - pts->InsertNextPoint(bounds[0],bounds[2],bounds[5]); - } - } - return pts; -} - +// zoom------------------------------------------------------------------------ void infinitiViewer::SetZoomScale(double scale) { - if (Renderer) - { - Renderer->GetActiveCamera()->SetParallelScale(scale); - } + if (Renderer) { + Renderer->GetActiveCamera()->SetParallelScale(scale); + } } void infinitiViewer::ResetZoomScaleToFitWindowSize() { - vtkImageData * inputData = nullptr; - if (Renderer && (inputData = GetInput())){ - double proj[4] ={0,0,0,1}; + vtkImageData *inputData = nullptr; + if (Renderer && (inputData = GetInput())) { + double proj[4] = {0, 0, 0, 1}; Renderer->GetActiveCamera()->GetDirectionOfProjection(proj); - double viewUp[4]= {0,0,0,1}; + double viewUp[4] = {0, 0, 0, 1}; this->Renderer->GetActiveCamera()->GetViewUp(viewUp); - double viewRight[4]= {0,0,0,1}; - vtkMath::Cross(viewUp,proj,viewRight); - int upIndex = (int) abs(round(1.0*viewUp[1]+2.0*viewUp[2])); - int rightIndex = (int)abs(round(1.0*viewRight[1]+2.0*viewRight[2])); - int* size = this->RenderWindow->GetSize(); + double viewRight[4] = {0, 0, 0, 1}; + vtkMath::Cross(viewUp, proj, viewRight); + int upIndex = (int) abs(round(1.0 * viewUp[1] + 2.0 * viewUp[2])); + int rightIndex = (int) abs(round(1.0 * viewRight[1] + 2.0 * viewRight[2])); + int *size = this->RenderWindow->GetSize(); double whFactor = 0.5; - double ws = 1.0* size[0]; - double hs = 1.0* size[1]; - double* bounds = inputData->GetBounds(); - double hp = fabs(1.0 * (bounds[upIndex*2+1] - bounds[upIndex*2])); - double wp = fabs(1.0 * (bounds[rightIndex*2+1] - bounds[rightIndex*2])); + double ws = 1.0 * size[0]; + double hs = 1.0 * size[1]; + double *bounds = inputData->GetBounds(); + double hp = fabs(1.0 * (bounds[upIndex * 2 + 1] - bounds[upIndex * 2])); + double wp = fabs(1.0 * (bounds[rightIndex * 2 + 1] - bounds[rightIndex * 2])); //because Parallel Scale is campare with half height - if(wp/hp>ws/hs){ - double aspect = hs/ws; - SetZoomScale((wp)*aspect*0.5+3.0); + if (wp / hp > ws / hs) { + double aspect = hs / ws; + SetZoomScale((wp) * aspect * 0.5 + 3.0); + } else { + SetZoomScale((hp) * 0.5 + 3.0); } - else{ - SetZoomScale((hp)*0.5+3.0); - } - } - else{ + } else { SetZoomScale(1.0); } } -void infinitiViewer::SetPanOffset(const double* p) { - double fp[3] = { 0.0,0.0,0.0 }; - Renderer->GetActiveCamera()->GetPosition(fp); - fp[0] = fp[0] + p[0]; - fp[1] = fp[1] + p[1]; - fp[2] = fp[2] + p[2]; - Renderer->GetActiveCamera()->SetPosition(fp); - Renderer->GetActiveCamera()->GetFocalPoint(fp); - fp[0] = fp[0] + p[0]; - fp[1] = fp[1] + p[1]; - fp[2] = fp[2] + p[2]; - Renderer->GetActiveCamera()->SetFocalPoint(fp); +// pan------------------------------------------------------------------------- +void infinitiViewer::SetPanOffset(const double *p) { + double fp[3] = {0.0, 0.0, 0.0}; + Renderer->GetActiveCamera()->GetPosition(fp); + fp[0] = fp[0] + p[0]; + fp[1] = fp[1] + p[1]; + fp[2] = fp[2] + p[2]; + Renderer->GetActiveCamera()->SetPosition(fp); + Renderer->GetActiveCamera()->GetFocalPoint(fp); + fp[0] = fp[0] + p[0]; + fp[1] = fp[1] + p[1]; + fp[2] = fp[2] + p[2]; + Renderer->GetActiveCamera()->SetFocalPoint(fp); } -//---------------------------------------------------------------------------- -void infinitiViewer::SetPosition(int x, int y) -{ - this->RenderWindow->SetPosition(x, y); +// window---------------------------------------------------------------------- +double infinitiViewer::GetColorWindow() { + return this->ImageActor->GetProperty()->GetColorWindow(); } -//---------------------------------------------------------------------------- -int* infinitiViewer::GetPosition() -{ - return this->RenderWindow->GetPosition(); +double infinitiViewer::GetColorLevel() { + return this->ImageActor->GetProperty()->GetColorLevel(); } -//---------------------------------------------------------------------------- -void infinitiViewer::SetDisplayId(void* a) -{ - this->RenderWindow->SetDisplayId(a); +void infinitiViewer::SetColorWindow(double s) { + this->ImageActor->GetProperty()->SetColorWindow(s); } -//---------------------------------------------------------------------------- -void infinitiViewer::SetWindowId(void* a) -{ - this->RenderWindow->SetWindowId(a); +void infinitiViewer::SetColorLevel(double s) { + this->ImageActor->GetProperty()->SetColorLevel(s); } -//---------------------------------------------------------------------------- -void infinitiViewer::SetParentId(void* a) -{ - this->RenderWindow->SetParentId(a); +void infinitiViewer::SetNegativeMode(bool negative) { + if (negative) { + double window = this->ImageActor->GetProperty()->GetColorWindow(); + double level = this->ImageActor->GetProperty()->GetColorLevel(); + + vtkNew lut; + lut->SetRange(level - 0.5 * window, level + 0.5 * window); // image intensity range + lut->SetValueRange(1.0, 0.0); // from black to white + lut->SetHueRange(0.0, 0.0); + lut->SetSaturationRange(0.0, 0.0); + //lookupTable->SetRampToLinear(); + lut->Build(); + this->SetLookupTable(lut); + this->Render(); + } else { + this->SetLookupTable(nullptr); + this->Render(); + } } -//---------------------------------------------------------------------------- -double infinitiViewer::GetColorWindow() -{ - return this->ImageActor->GetProperty()->GetColorWindow(); +void infinitiViewer::SetLookupTable(vtkLookupTable *lut) { + this->ImageActor->GetProperty()->SetLookupTable(lut); } -//---------------------------------------------------------------------------- -double infinitiViewer::GetColorLevel() -{ - return this->ImageActor->GetProperty()->GetColorLevel(); +// fusion---------------------------------------------------------------------- +bool simpleFusionableCheck(vtkImageData *a, vtkImageData *b) { + double *origin1 = a->GetOrigin(); + double *origin2 = b->GetOrigin(); + return (origin1[0] == origin2[0]) && (origin1[1] == origin2[1]) && (origin1[2] == origin2[2]); } -//---------------------------------------------------------------------------- -void infinitiViewer::SetColorWindow(double s) -{ - this->ImageActor->GetProperty()->SetColorWindow(s); +void infinitiViewer::SetFusionInputData(vtkImageData *data) { + if (!this->GetInput()) return; + if (!simpleFusionableCheck(data, this->GetInput())) return; + if (!this->FusionMapper) { + this->FusionMapper = vtkImageSliceMapper::New(); + this->FusionMapper->SliceAtFocalPointOn(); + this->FusionMapper->SliceFacesCameraOn(); + + FusionMapper->SetInputData(data); + this->FusionActor = vtkImageSlice::New(); + //must set fusion image slice layer to 1 to make main image is active layer of image stack + FusionActor->GetProperty()->SetLayerNumber(1); + FusionActor->SetPickable(false); + FusionActor->SetMapper(FusionMapper); + } else if (data == FusionMapper->GetInput()) return; + const auto prop = FusionActor->GetProperty(); + if (firstFusion) { + vtkNew table; + table->SetHueRange(1.0, 0.0); + table->SetSaturationRange(0.5, 1.0); + table->SetValueRange(0.0, 1.0); + table->SetAboveRangeColor(0.0, 0.0, 0.0, 0.0); + table->SetBelowRangeColor(0.0, 0.0, 0.0, 0.0); + table->SetNumberOfColors(512); + table->UseAboveRangeColorOn(); + table->UseBelowRangeColorOn(); + table->SetAlpha(FusionOpacity); + table->Build(); + prop->SetLookupTable(table); + firstFusion = false; + } +#ifdef IN_TEST_MODE + //vtkTextProperty* vtkTextProperty = vtkTextProperty::New(); + vtkNew LabelTextProperty; + LabelTextProperty->SetFontSize(16); + LabelTextProperty->SetBold(1); + LabelTextProperty->SetItalic(1); + LabelTextProperty->SetShadow(1); + LabelTextProperty->SetFontFamilyToArial(); + + + bar = vtkScalarBarActor::New(); + bar->GetPositionCoordinate()->SetCoordinateSystemToNormalizedViewport(); + bar->SetLookupTable(prop->GetLookupTable()); + bar->SetWidth(0.1); + bar->SetHeight(0.4); + bar->SetPosition(0.04, 0.4); + //bar->DrawFrameOn(); + bar->SetMaximumHeightInPixels(250); + bar->SetMaximumWidthInPixels(50); + + bar->SetNumberOfLabels(2); + bar->SetLabelFormat("%.0f"); + + bar->UnconstrainedFontSizeOff(); + bar->SetUnconstrainedFontSize(true); + bar->SetLabelTextProperty(LabelTextProperty); + this->Renderer->AddActor(bar); + + + OpacityActor = vtkTextActor::New(); + //OpacityActor->SetInput("50%"); + OpacityActor->GetPositionCoordinate()->SetCoordinateSystemToNormalizedViewport(); + OpacityActor->SetPosition(0.04, 0.35); + OpacityActor->SetTextProperty(LabelTextProperty); + SetScalarBarTitle(FusionOpacity); + + + this->Renderer->AddActor(OpacityActor); +#endif + } -//---------------------------------------------------------------------------- -void infinitiViewer::SetColorLevel(double s) -{ - this->ImageActor->GetProperty()->SetColorLevel(s); +void infinitiViewer::SetFusionColorLeveL(double level) { + if (FusionActor) { + FusionActor->GetProperty()->SetColorLevel(level); + PrepareFusionColorTable(FusionActor->GetProperty()->GetLookupTable()); + } } -void infinitiViewer::SetNegativeMode(bool negative) -{ - if (negative) { - double window = this->ImageActor->GetProperty()->GetColorWindow(); - double level = this->ImageActor->GetProperty()->GetColorLevel(); - - vtkNew lut; - lut->SetRange(level - 0.5 * window, level + 0.5 * window); // image intensity range - lut->SetValueRange(1.0, 0.0); // from black to white - lut->SetHueRange(0.0, 0.0); - lut->SetSaturationRange(0.0, 0.0); - //lookupTable->SetRampToLinear(); - lut->Build(); - this->SetLookupTable(lut); - this->Render(); - } - else - { - this->SetLookupTable(nullptr); - this->Render(); - } +void infinitiViewer::SetFusionColorWindow(double window) { + if (FusionActor) { + FusionActor->GetProperty()->SetColorWindow(window); + PrepareFusionColorTable(FusionActor->GetProperty()->GetLookupTable()); + } } -void infinitiViewer::SetLookupTable(vtkLookupTable* lut) -{ - this->ImageActor->GetProperty()->SetLookupTable(lut); +void infinitiViewer::SetScalarBarTitle(double FusionOpa) { + int opa = int(FusionOpa * 100); + std::string str_opa = std::to_string(opa); + str_opa.append("%"); + OpacityActor->SetInput(str_opa.c_str()); } - -//---------------------------------------------------------------------------- -void infinitiViewer::InstallPipeline() -{ - if (this->RenderWindow && this->Renderer) - { - this->RenderWindow->AddRenderer(this->Renderer); - } - - if (this->Interactor) - { - if (!this->InteractorStyle) - { - this->InteractorStyle = ActorDraggableInteractorStyle::New(); - this->InteractorStyle->SetInteractionModeToImageSlicing(); - this->InteractorStyle->SetCurrentImageNumber(0); - this->InteractorStyle->SetCornerAnnotation(cornerAnnotation); - - this->InteractorStyle->AddObserver(ActorDraggableInteractorStyle::DraggableStyleEvents::EndMeasureEvent, this, &infinitiViewer::AddMeasures); - this->InteractorStyle->AddObserver(ActorDraggableInteractorStyle::DraggableStyleEvents::DeleteMeasureEvent, this, &infinitiViewer::RemoveMeasures); - this->InteractorStyle->AddObserver(ActorDraggableInteractorStyle::DraggableStyleEvents::SliceEvent, this, &infinitiViewer::ChangeSlice); - this->InteractorStyle->AddObserver(ActorDraggableInteractorStyle::DraggableStyleEvents::SlicedEvent, this, &infinitiViewer::LoadMeasures); - InteractorStyle->AddObserver(ActorDraggableInteractorStyle::SlicedEvent, this, &infinitiViewer::updateTopLeftCornerInfo); - - //for convert vtkEvent to Qt signal - this->InteractorStyle->AddObserver(ActorDraggableInteractorStyle::DraggableStyleEvents::SlicedEvent, this, &infinitiViewer::raiseEvent); - this->InteractorStyle->AddObserver(ActorDraggableInteractorStyle::DraggableStyleEvents::EndDollyEvent, this, &infinitiViewer::raiseEvent); - this->InteractorStyle->AddObserver(vtkCommand::EventIds::EndWindowLevelEvent, this, &infinitiViewer::raiseEvent); - this->InteractorStyle->AddObserver(vtkCommand::EventIds::EndPanEvent, this, &infinitiViewer::raiseEvent); - } - - this->Interactor->SetInteractorStyle(this->InteractorStyle); - this->Interactor->SetRenderWindow(this->RenderWindow); - } - - if (this->Renderer && this->ImageActor) - { - this->Renderer->AddViewProp(this->ImageStack); -// this->Renderer->AddViewProp(this->ImageActor); - this->Renderer->GetActiveCamera()->SetParallelProjection(1); - this->Renderer->SetBackground(0.0, 0.0, 0.0); - } - if (this->Renderer && this->FusionActor && Fusion) - { - this->ImageStack->AddImage(this->FusionActor); - } - if (this->Renderer && this->cornerAnnotation) - { - this->Renderer->AddViewProp(cornerAnnotation); - } - loadedMeasureSlice = -1; +void infinitiViewer::IncreFusionOpacity(double percent) { + if (FusionActor) { + FusionOpacity += percent; + FusionOpacity = FusionOpacity > 1.0 ? 1.0 : FusionOpacity; + FusionOpacity = FusionOpacity < 0.0 ? 0.0 : FusionOpacity; + SetScalarBarTitle(FusionOpacity); + FusionActor->GetProperty()->GetLookupTable()->SetAlpha(FusionOpacity); + PrepareFusionColorTable(FusionActor->GetProperty()->GetLookupTable()); + } } -//---------------------------------------------------------------------------- -void infinitiViewer::UnInstallPipeline() -{ - if (this->ImageActor && this->ImageMapper) - { - // this->ImageActor->SetMapper(nullptr); - } - if (this->Renderer && this->FusionActor && this->Renderer->HasViewProp(FusionActor)) - { - this->Renderer->RemoveViewProp(this->FusionActor); - } - if (this->Renderer && this->ImageActor) - { - this->Renderer->RemoveViewProp(this->ImageActor); - } +void infinitiViewer::SetFusionOpacity(double opacity) { + if (FusionActor) { + opacity = opacity > 1.0 ? 1.0 : opacity; + opacity = opacity < 0.0 ? 0.0 : opacity; + FusionOpacity = opacity; + SetScalarBarTitle(FusionOpacity); + FusionActor->GetProperty()->GetLookupTable()->SetAlpha(FusionOpacity); + PrepareFusionColorTable(FusionActor->GetProperty()->GetLookupTable()); + } +} - if (this->RenderWindow && this->Renderer) - { - this->RenderWindow->RemoveRenderer(this->Renderer); - } +void prepareLookTable(vtkLookupTable *table) { + table->SetAboveRangeColor(0.0, 0.0, 0.0, 0.0); + table->SetBelowRangeColor(0.0, 0.0, 0.0, 0.0); + table->UseAboveRangeColorOn(); + table->UseBelowRangeColorOn(); +} - if (this->Interactor) - { - this->Interactor->SetInteractorStyle(nullptr); - this->Interactor->SetRenderWindow(nullptr); - } +void prepareTransferFunction(vtkDiscretizableColorTransferFunction *table, vtkImageProperty *prop, + const std::vector> &vector) { + + double min = prop->GetColorLevel() - prop->GetColorWindow() * 0.5; + double max = prop->GetColorLevel() + prop->GetColorWindow() * 0.5; + int size = table->GetSize(); + + table->RemoveAllPoints(); + for (int i = 0; i < size; i++) { + table->AddRGBPoint(min + vector[i][0] * prop->GetColorWindow(), + vector[i][1], vector[i][2], vector[i][3], vector[i][4], vector[i][5]); + } + vtkNew wise; + wise->AddPoint(min - 0.05, 0.0); + wise->AddPoint(min, table->GetAlpha()); + wise->AddPoint(max, table->GetAlpha()); + //wise->AddPoint(max + 0.05, 0.0); + wise->ClampingOn(); //Default is On + table->SetScalarOpacityFunction(wise); + table->EnableOpacityMappingOn(); +} + +void infinitiViewer::SetFusionColorTable(vtkScalarsToColors *table) { + if (!FusionActor) return; + PrepareFusionColorTable(table, true); + FusionActor->GetProperty()->SetLookupTable(table); +#ifdef IN_TEST_MODE + bar->SetLookupTable(table); +#endif +} + +void infinitiViewer::SetFusionColorPreset(const char *preset) { + auto values = ColorMapReader::DefaultPresets()->GetPresetValues(preset); + auto PresetType = ColorMapReader::DefaultPresets()->GetPresetType(preset); + + switch (PresetType) { + case ColorMapReader::RGBPoints: { + vtkNew table; + for (int i = 0; i + 3 < values.size(); i += 4) { + table->AddRGBPoint(values[i], values[i + 1], values[i + 2], values[i + 3]); + } + double *nancolor = ColorMapReader::DefaultPresets()->GetPresetNanColor(preset); + if (nancolor) { + table->SetNanColor(nancolor); + } + this->SetFusionColorTable(table); + break; + } + case ColorMapReader::IndexedColors: { + vtkNew table; + for (int i = 0; i + 2 < values.size() - 1; i += 2) { + table->AddRGBPoint(((double) i) / ((double) (values.size() - 3)), values[i], values[i + 1], + values[i + 2], 1.0, 1.0); + table->AddRGBPoint(1.0, values[values.size() - 3], values[values.size() - 2], + values[values.size() - 1]); + double *nancolor = ColorMapReader::DefaultPresets()->GetPresetNanColor(preset); + if (nancolor) { + table->SetNanColor(nancolor); + } + this->SetFusionColorTable(table); + break; + } + } + default: + break; + } +} + +void infinitiViewer::PrepareFusionColorTable(vtkScalarsToColors *table, bool reset) { + const auto prop = FusionActor->GetProperty(); + table->SetAlpha(FusionOpacity); + if (table->IsA("vtkLookupTable")) { + auto t = vtkLookupTable::SafeDownCast(table); + if (!t) return; + prepareLookTable(t); + } else if (table->IsA("vtkDiscretizableColorTransferFunction")) { + auto t = vtkDiscretizableColorTransferFunction::SafeDownCast(table); + if (!t) return; + if (reset) { + int size = t->GetSize(); + fusion_tf_vector.clear(); + for (int i = 0; i < size; i++) { + double v[6] = {0, 0, 0, 0, 0, 0}; + t->GetNodeValue(i, v); + std::vector nt = {v[0], v[1], v[2], v[3], v[4], v[5]}; + fusion_tf_vector.push_back(nt); + } + } + prepareTransferFunction(t, prop, fusion_tf_vector); + } + table->Build(); +} + +void infinitiViewer::RemoveFusionActor() { + this->Renderer->RemoveActor(bar); + bar->Delete(); + bar = nullptr; + this->Renderer->RemoveActor(OpacityActor); + OpacityActor->Delete(); + OpacityActor = nullptr; +} + +void infinitiViewer::RemoveFusionData() { + if (!FusionMapper) return; + if (ImageStack->HasImage(FusionActor)) { + ImageStack->RemoveImage(FusionActor); + } + FusionMapper->Delete(); + FusionMapper = nullptr; + FusionActor->Delete(); + FusionActor = nullptr; + //reset first fusion flag + firstFusion = true; + + RemoveFusionActor(); + //this->Render(); +} + +void infinitiViewer::SwitchToNextPreset() { + if (ColorMapReader::DefaultPresets()) { + + //const char* preset3 = ColorMapReader::DefaultPresets()->GetPresetNames().at(currentPresetIndex).data(); + //const string& preset = ColorMapReader::DefaultPresets()->GetPresetNames().at(currentPresetIndex); + string preset = ColorMapReader::DefaultPresets()->GetPresetNames().at(currentPresetIndex); + currentPresetIndex++; + currentPresetIndex = currentPresetIndex > 193 ? 0 : currentPresetIndex; + SetFusionColorPreset(preset.c_str()); + this->Render(); + } +} + +// window about---------------------------------------------------------------- +void infinitiViewer::SetPosition(int x, int y) { + this->RenderWindow->SetPosition(x, y); +} + +int *infinitiViewer::GetPosition() { + return this->RenderWindow->GetPosition(); +} + +void infinitiViewer::SetDisplayId(void *a) { + this->RenderWindow->SetDisplayId(a); +} + +void infinitiViewer::SetWindowId(void *a) { + this->RenderWindow->SetWindowId(a); +} + +const char *infinitiViewer::GetWindowName() { + return this->RenderWindow->GetWindowName(); +} + +void infinitiViewer::SetParentId(void *a) { + this->RenderWindow->SetParentId(a); +} + +// measure-------------------------------------------------------------------- +void infinitiViewer::ActiveMeasure(Measure *m) { + this->InteractorStyle->ActiveMeasure(m); +} + +void infinitiViewer::UnActiveMeasure() { + this->InteractorStyle->UnActiveMeasure(); } void infinitiViewer::LoadMeasures(bool forceReload) { - if (!forceReload && this->loadedMeasureSlice == this->ImageMapper->GetSliceNumber()) return; + if (!forceReload && this->loadedMeasureSlice == this->ImageMapper->GetSliceNumber()) return; - this->loadedMeasureSlice = this->ImageMapper->GetSliceNumber(); - ClearCurrentSliceMeasure(); - ReloadCurrentSliceMeasure(); + this->loadedMeasureSlice = this->ImageMapper->GetSliceNumber(); + ClearCurrentSliceMeasure(); + ReloadCurrentSliceMeasure(); } void infinitiViewer::ReloadCurrentSliceMeasure() { - list = measureStore->GetMeasures(SOP_UID, this->SliceOrientation, ImageMapper->GetSliceNumber()); + list = measureStore->GetMeasures(SOP_UID, this->SliceOrientation, ImageMapper->GetSliceNumber()); - if (list) - { - for (int i = 0; i < list->length(); i++) { - auto item = list->value(i); - auto d = dynamic_cast(item); - if (d) d->SetRenderer(GetRenderer()); - } - } + if (list) { + for (int i = 0; i < list->length(); i++) { + auto item = list->value(i); + auto d = dynamic_cast(item); + if (d) d->SetRenderer(GetRenderer()); + } + } } void infinitiViewer::ClearCurrentSliceMeasure() const { - if (list) - { - for (int i = 0; i < list->length(); i++) { - auto item = list->value(i); - auto d = dynamic_cast(item); - if (d) d->SetRenderer(nullptr); - } - } + if (list) { + for (int i = 0; i < list->length(); i++) { + auto item = list->value(i); + auto d = dynamic_cast(item); + if (d) d->SetRenderer(nullptr); + } + } } -void infinitiViewer::AddMeasures(vtkObject*, unsigned long eventid, void* calldata) { - auto m = static_cast(calldata); - if (m->Valid()) { - measureStore->Store(SOP_UID, this->SliceOrientation,this->ImageMapper->GetSliceNumber(), m); - } - LoadMeasures(true); - this->Render(); +void infinitiViewer::AddMeasures(vtkObject *, unsigned long eventid, void *calldata) { + auto m = static_cast(calldata); + if (m->Valid()) { + measureStore->Store(SOP_UID, this->SliceOrientation, this->ImageMapper->GetSliceNumber(), m); + } + LoadMeasures(true); + this->Render(); } -void infinitiViewer::RemoveMeasures(vtkObject*, unsigned long eventid, void* calldata) { - auto p = static_cast(calldata); - auto da = DraggableActor::SafeDownCast(p); - auto m = dynamic_cast(da); - ClearCurrentSliceMeasure(); - measureStore->Remove(m); - this->InteractorStyle->ClearSelectedProp(); - ReloadCurrentSliceMeasure(); - this->Render(); +void infinitiViewer::RemoveMeasures(vtkObject *, unsigned long eventid, void *calldata) { + auto p = static_cast(calldata); + auto da = DraggableActor::SafeDownCast(p); + auto m = dynamic_cast(da); + ClearCurrentSliceMeasure(); + measureStore->Remove(m); + this->InteractorStyle->ClearSelectedProp(); + ReloadCurrentSliceMeasure(); + this->Render(); } void infinitiViewer::DeleteSelectedMeasure() { - if (this->InteractorStyle->GetSelectedProp()) - { - RemoveMeasures(nullptr, 0, this->InteractorStyle->GetSelectedProp()); - } + if (this->InteractorStyle->GetSelectedProp()) { + RemoveMeasures(nullptr, 0, this->InteractorStyle->GetSelectedProp()); + } } void infinitiViewer::DeleteCurrentSliceMeasure() { - this->InteractorStyle->ClearSelectedProp(); - ClearCurrentSliceMeasure(); - measureStore->RemoveAllInSlice(SOP_UID, this->SliceOrientation, this->ImageMapper->GetSliceNumber()); - ReloadCurrentSliceMeasure(); - this->Render(); + this->InteractorStyle->ClearSelectedProp(); + ClearCurrentSliceMeasure(); + measureStore->RemoveAllInSlice(SOP_UID, this->SliceOrientation, this->ImageMapper->GetSliceNumber()); + ReloadCurrentSliceMeasure(); + this->Render(); } void infinitiViewer::DeleteCurrentSeriesMeasure() { - this->InteractorStyle->ClearSelectedProp(); - ClearCurrentSliceMeasure(); - measureStore->RemoveAllInSeries(SOP_UID); - ReloadCurrentSliceMeasure(); - this->Render(); -} - -//---------------------------------------------------------------------------- -void infinitiViewer::Render() -{ - if (this->FirstRender) - { - // // Initialize the size if not set yet - - vtkAlgorithm* input = this->GetInputAlgorithm(); - if (input) - { - input->UpdateInformation(); - int* w_ext = - this->GetInputInformation()->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()); - int xs = 0, ys = 0; - - switch (this->SliceOrientation) - { - case infinitiViewer::SLICE_ORIENTATION_XY: - default: - xs = w_ext[1] - w_ext[0] + 1; - ys = w_ext[3] - w_ext[2] + 1; - break; - - case infinitiViewer::SLICE_ORIENTATION_XZ: - xs = w_ext[1] - w_ext[0] + 1; - ys = w_ext[5] - w_ext[4] + 1; - break; - - case infinitiViewer::SLICE_ORIENTATION_YZ: - xs = w_ext[3] - w_ext[2] + 1; - ys = w_ext[5] - w_ext[4] + 1; - break; - } - - // if it would be smaller than 150 by 100 then limit to 150 by 100 - if (this->RenderWindow->GetSize()[0] == 0) - { - this->RenderWindow->SetSize(xs < 150 ? 150 : xs, ys < 100 ? 100 : ys); - } - - if (this->Renderer) - { - this->Renderer->ResetCamera(); - auto camera = this->Renderer->GetActiveCamera(); - //camera 必须要动一下,直接loadfusion才能正常显示 - int lastIndex = ImageMapper->GetSliceNumber(); - //camera->GetPosition(cameraPosition); - double distance = camera->GetDistance(); - camera->SetDistance(distance - 0.005); - //camera->GetPosition(cameraPosition); - int currentIndex = ImageMapper->GetSliceNumber(); - if (currentIndex != lastIndex) this->SetSlice(lastIndex); - ResetZoomScaleToFitWindowSize(); -// this->Renderer->GetActiveCamera()->SetParallelScale(xs < 150 ? 75 : (xs - 1) / 2.0); - //calibration of image by VFlip - //this->Renderer->GetActiveCamera()->Elevation(-180); - //this->Renderer->GetActiveCamera()->Roll(180); - //this->Renderer->ResetCameraClippingRange(); - - } - this->FirstRender = 0; - } - } - if (this->GetInput()) - { - if (Fusion && FusionActor && !this->ImageStack->HasImage(FusionActor)) { -// this->Renderer->AddActor(FusionActor); - - this->ImageStack->AddImage(FusionActor); - } - if (!Fusion && FusionActor && this->ImageStack->HasImage(FusionActor)) - { -// this->Renderer->RemoveViewProp(FusionActor); - this->ImageStack->RemoveImage(FusionActor); - - } - this->LoadMeasures(); - this->RenderWindow->Render(); - } -} - -//---------------------------------------------------------------------------- -const char* infinitiViewer::GetWindowName() -{ - return this->RenderWindow->GetWindowName(); -} - -//---------------------------------------------------------------------------- -void infinitiViewer::SetOffScreenRendering(vtkTypeBool i) -{ - this->RenderWindow->SetOffScreenRendering(i); -} - -//---------------------------------------------------------------------------- -vtkTypeBool infinitiViewer::GetOffScreenRendering() -{ - return this->RenderWindow->GetOffScreenRendering(); -} - -//---------------------------------------------------------------------------- -void infinitiViewer::SetInputData(vtkImageData* in) -{ -#ifdef _DEBUG - printf("fusion imageDataOrigin:%f,%f,%f", in->GetOrigin()[0], in->GetOrigin()[1], in->GetOrigin()[2]); - printf("fusion spacing:%f,%f,%f", in->GetSpacing()[0], in->GetSpacing()[1], in->GetSpacing()[2]); -#endif - this->FirstRender = 1; - this->ImageActor->GetMapper()->SetInputData(in); - this->RemoveFusionData(); - this->ActiveRuler(); - // this->UpdateDisplayExtent(); -} - -//---------------------------------------------------------------------------- -vtkImageData* infinitiViewer::GetInput() -{ - return this->ImageMapper->GetInput(); -} - -//---------------------------------------------------------------------------- -vtkInformation* infinitiViewer::GetInputInformation() -{ - return this->ImageMapper->GetInputInformation(); -} - -//---------------------------------------------------------------------------- -vtkAlgorithm* infinitiViewer::GetInputAlgorithm() -{ - return this->ImageMapper->GetInputAlgorithm(); -} - -//---------------------------------------------------------------------------- -void infinitiViewer::SetInputConnection(vtkAlgorithmOutput* input) -{ - this->ImageMapper->SetInputConnection(input); - this->RemoveFusionData(); -} - -void infinitiViewer::ActiveMeasure(Measure* m) { - this->InteractorStyle->ActiveMeasure(m); -} - - -void infinitiViewer::UnActiveMeasure() { - this->InteractorStyle->UnActiveMeasure(); -} - -//---------------------------------------------------------------------------- -void infinitiViewer::PrintSelf(ostream& os, vtkIndent indent) -{ - this->Superclass::PrintSelf(os, indent); - - os << indent << "RenderWindow:\n"; - this->RenderWindow->PrintSelf(os, indent.GetNextIndent()); - os << indent << "Renderer:\n"; - this->Renderer->PrintSelf(os, indent.GetNextIndent()); - os << indent << "ImageActor:\n"; - this->ImageActor->PrintSelf(os, indent.GetNextIndent()); - os << indent << "ImageMapper:\n" << endl; - this->ImageMapper->PrintSelf(os, indent.GetNextIndent()); - os << indent << "Slice: " << this->Slice << endl; - os << indent << "SliceOrientation: " << this->SliceOrientation << endl; - os << indent << "InteractorStyle: " << endl; - if (this->InteractorStyle) - { - os << "\n"; - this->InteractorStyle->PrintSelf(os, indent.GetNextIndent()); - } - else - { - os << "None"; - } -} - -void infinitiViewer::RenderRuler() { - if (AnnoHelper::IsAnno()) { - if (Renderer) - { - ruler->RenderOverlay(Renderer); - } - } -} - -void infinitiViewer::SwitchToNextPreset() -{ - if (ColorMapReader::DefaultPresets()) { - - //const char* preset3 = ColorMapReader::DefaultPresets()->GetPresetNames().at(currentPresetIndex).data(); - //const string& preset = ColorMapReader::DefaultPresets()->GetPresetNames().at(currentPresetIndex); - string preset = ColorMapReader::DefaultPresets()->GetPresetNames().at(currentPresetIndex); - printf("current preset name:%s\r\n", preset.c_str()); - currentPresetIndex++; - currentPresetIndex = currentPresetIndex > 193 ? 0 : currentPresetIndex; - SetFusionColorPreset(preset.c_str()); - this->Render(); - } + this->InteractorStyle->ClearSelectedProp(); + ClearCurrentSliceMeasure(); + measureStore->RemoveAllInSeries(SOP_UID); + ReloadCurrentSliceMeasure(); + this->Render(); } +// corner---------------------------------------------------------------------- // helper class to format slice status message -class StatusMessage -{ +class StatusMessage { public: - static std::string Format(int slice, int maxSlice) - { - std::stringstream tmp; - tmp << "Slice Number " << slice + 1 << "/" << maxSlice + 1; - return tmp.str(); - } - static std::string Format(std::string msg1, std::string msg2) - { - std::stringstream tmp; - tmp << msg1 << "\n" << msg2; - return tmp.str(); - } + static std::string Format(int slice, int maxSlice) { + std::stringstream tmp; + tmp << "Slice Number " << slice + 1 << "/" << maxSlice + 1; + return tmp.str(); + } + + static std::string Format(std::string msg1, std::string msg2) { + std::stringstream tmp; + tmp << msg1 << "\n" << msg2; + return tmp.str(); + } }; +void infinitiViewer::InitCornerInfo(ExtendMedicalImageProperties *pSeries) { + // mono and has preset + if (pSeries->GetNumberOfWindowLevelPresets() > 0 && pSeries->GetSamplePerPixel() == 1) { + double *wwwl = pSeries->GetNthWindowLevelPreset(0); + m_cornerInfo.win_level = (int) wwwl[1]; + m_cornerInfo.win_width = (int) wwwl[0]; + } + // no preset or color image + else { + m_cornerInfo.win_level = 128; + m_cornerInfo.win_width = 256; + } -//---------------------------------------------------------------------------- -void infinitiViewer::SetSliceOrientation(int orientation) -{ + char buffer[sizeof(long) * 8 + 1]; + const char *s = ltoa(pSeries->GetFileNames().size(), buffer, 10); + m_cornerInfo.ConstAnno[TOP_LEFT].clear(); + m_cornerInfo.ConstAnno[TOP_LEFT].append(buffer); + m_cornerInfo.ConstAnno[TOP_LEFT].append(" "); + m_cornerInfo.ConstAnno[TOP_LEFT].append(pSeries->GetSeriesNumber()); + + m_cornerInfo.ConstAnno[TOP_RIGHT].clear(); + m_cornerInfo.ConstAnno[TOP_RIGHT].append(pSeries->GetPatientName()); + m_cornerInfo.ConstAnno[TOP_RIGHT].append("\n"); + m_cornerInfo.ConstAnno[TOP_RIGHT].append(pSeries->GetStudyDescription()); + m_cornerInfo.ConstAnno[TOP_RIGHT].append("\n"); + m_cornerInfo.ConstAnno[TOP_RIGHT].append(pSeries->GetSeriesDescription()); + m_cornerInfo.ConstAnno[TOP_RIGHT].append("\n"); + m_cornerInfo.ConstAnno[TOP_RIGHT].append(pSeries->GetInstitutionName()); + m_cornerInfo.ConstAnno[TOP_RIGHT].append("\n"); + + m_cornerInfo.ConstAnno[TOP_RIGHT_PRIVACY].clear(); + m_cornerInfo.ConstAnno[TOP_RIGHT_PRIVACY].append("****"); + m_cornerInfo.ConstAnno[TOP_RIGHT_PRIVACY].append("\n"); + m_cornerInfo.ConstAnno[TOP_RIGHT_PRIVACY].append(pSeries->GetStudyDescription()); + m_cornerInfo.ConstAnno[TOP_RIGHT_PRIVACY].append("\n"); + m_cornerInfo.ConstAnno[TOP_RIGHT_PRIVACY].append(pSeries->GetSeriesDescription()); + m_cornerInfo.ConstAnno[TOP_RIGHT_PRIVACY].append("\n"); + m_cornerInfo.ConstAnno[TOP_RIGHT_PRIVACY].append("****"); + m_cornerInfo.ConstAnno[TOP_RIGHT_PRIVACY].append("\n"); + + double *d = pSeries->GetDirectionCosine(); + double xVector[3] = {d[0], d[1], d[2]}; + double yVector[3] = {d[3], d[4], d[5]}; + double zVector[3] = {0, 0, 0}; + vtkMath::Cross(xVector, yVector, zVector); + + + matrix->Zero(); + matrix->SetElement(0, 0, xVector[0]); + matrix->SetElement(1, 0, xVector[1]); + matrix->SetElement(2, 0, xVector[2]); + matrix->SetElement(0, 1, yVector[0]); + matrix->SetElement(1, 1, yVector[1]); + matrix->SetElement(2, 1, yVector[2]); + matrix->SetElement(0, 2, zVector[0]); + matrix->SetElement(1, 2, zVector[1]); + matrix->SetElement(2, 2, zVector[2]); + matrix->SetElement(3, 3, 1); +// matrix->Invert(); + + double *p = pSeries->GetPosition(); + imageDataOrigin[0] = p[0]; + imageDataOrigin[1] = p[1]; + imageDataOrigin[2] = p[2]; +} + +void infinitiViewer::InitTopLeftCornerInfo(const std::string &lbl_ser_num, const std::string &ser_num) { + m_cornerInfo.ConstAnno[TOP_LEFT].append(lbl_ser_num); + m_cornerInfo.ConstAnno[TOP_LEFT].append(" "); + m_cornerInfo.ConstAnno[TOP_LEFT].append(ser_num); +} + +void infinitiViewer::UpdateCornerInfo(int index) { + if (AnnoHelper::IsAnno()) { + + if (index == TOP_LEFT) { + int maxSlice = this->GetSliceMax(); + int currentSlice = this->GetSlice(); + //cout << "MoveSliceForward::Slice = " << _Slice << std::endl; + std::string msg_const = m_cornerInfo.ConstAnno[index]; + std::string msg_var = StatusMessage::Format(currentSlice, maxSlice); + std::string msg_upleft = StatusMessage::Format(msg_var, msg_const); + //_StatusMapper->SetInput(msg.c_str()); + cornerAnnotation->SetText(index, msg_upleft.c_str()); + + } else if (index == BOTTOM_RIGHT) { + std::string message = "WL/WW:"; + message += vtkVariant((int) this->GetColorLevel()).ToString(); + message += " / "; + message += vtkVariant((int) this->GetColorWindow()).ToString(); + + + cornerAnnotation->SetText(index, message.c_str()); + //m_renderWindowInteractor->Render(); + + //m_imageViewer->Modified(); + } else if (index == TOP_RIGHT) { + if (AnnoHelper::IsPrivacy()) { + cornerAnnotation->SetText(index, m_cornerInfo.ConstAnno[TOP_RIGHT_PRIVACY].c_str()); + } else { + cornerAnnotation->SetText(index, m_cornerInfo.ConstAnno[index].c_str()); + } + + } else { + cornerAnnotation->SetText(index, m_cornerInfo.ConstAnno[index].c_str()); + } + } + this->Render(); +} + +void infinitiViewer::UpdateCornerInfoAll() { + if (AnnoHelper::IsAnno()) { + UpdateCornerInfo(TOP_LEFT); + UpdateCornerInfo(BOTTOM_RIGHT); + UpdateCornerInfo(TOP_RIGHT); + + + UpdateCornerInfo(BOTTOM_MIDDLE); + UpdateCornerInfo(RIGHT_MIDDLE); + UpdateCornerInfo(LEFT_MIDDLE); + UpdateCornerInfo(TOP_MIDDLE); + } else { + cornerAnnotation->ClearAllTexts(); + this->Render(); + } +} + +void infinitiViewer::UpdateTopLeftCornerInfo() { + if (AnnoHelper::IsAnno()) { + int maxSlice = this->GetSliceMax(); + int currentSlice = this->GetSlice(); + std::string msg_const = m_cornerInfo.ConstAnno[TOP_LEFT]; + std::string msg_var = StatusMessage::Format(currentSlice, maxSlice); + std::string msg_upleft = StatusMessage::Format(msg_var, msg_const); + cornerAnnotation->SetText(TOP_LEFT, msg_upleft.c_str()); + } + this->Render(); +} + +// SliceOrientation------------------------------------------------------------ +void infinitiViewer::SetSliceOrientation(int orientation) { if (orientation < infinitiViewer::SLICE_ORIENTATION_YZ || - orientation > infinitiViewer::SLICE_ORIENTATION_XY) - { + orientation > infinitiViewer::SLICE_ORIENTATION_XY) { vtkErrorMacro("Error - invalid slice orientation " << orientation); return; } - if (this->SliceOrientation == orientation) - { + if (this->SliceOrientation == orientation) { return; } @@ -1212,18 +1163,16 @@ void infinitiViewer::SetSliceOrientation(int orientation) // Update the viewer - int* range = this->GetSliceRange(); - if (range) - { + int *range = this->GetSliceRange(); + if (range) { this->Slice = static_cast((range[0] + range[1]) * 0.5); } this->UpdateOrientation(); - updateOrienInfo(); + UpdateOrientationInfo(); // this->UpdateDisplayExtent(); - if (this->Renderer && this->GetInput()) - { + if (this->Renderer && this->GetInput()) { this->Renderer->ResetCamera(); ResetZoomScaleToFitWindowSize(); } @@ -1233,38 +1182,41 @@ void infinitiViewer::SetSliceOrientation(int orientation) SetSlice(0); } -//---------------------------------------------------------------------------- -void infinitiViewer::UpdateOrientation() -{ +int infinitiViewer::GetWorldSliceOrientation() { + double orientations[4] = {.0, .0, .0, 1.0}; + orientations[SliceOrientation] = 1.0; + matrix->MultiplyPoint(orientations, orientations); + return (int) abs(round(1.0 * orientations[1]) + round(2.0 * orientations[2])); +} + +// Orientation (with corner text)---------------------------------------------- +void infinitiViewer::UpdateOrientation() { // Set the camera position - vtkCamera* cam = this->Renderer ? this->Renderer->GetActiveCamera() : nullptr; - if (cam) - { + vtkCamera *cam = this->Renderer ? this->Renderer->GetActiveCamera() : nullptr; + if (cam) { - switch (this->SliceOrientation) - { - case infinitiViewer::SLICE_ORIENTATION_XY: - { + switch (this->SliceOrientation) { + case infinitiViewer::SLICE_ORIENTATION_XY: { cam->SetFocalPoint(0, 0, 0); cam->SetPosition(0, 0, -1); // -1 if medical ? cam->SetViewUp(0, -1, 0); break; } - case infinitiViewer::SLICE_ORIENTATION_XZ:{ + case infinitiViewer::SLICE_ORIENTATION_XZ: { double zVec = GetInput()->GetSpacing()[2]; - double upVal = (zVec > 0.0?1.0:-1.0); + double upVal = (zVec > 0.0 ? 1.0 : -1.0); cam->SetFocalPoint(0, 0, 0); - cam->SetPosition(0, 1*upVal, 0); // 1 if medical ? - cam->SetViewUp(0, 0, -1.0 *upVal); + cam->SetPosition(0, 1 * upVal, 0); // 1 if medical ? + cam->SetViewUp(0, 0, -1.0 * upVal); break; } - case infinitiViewer::SLICE_ORIENTATION_YZ:{ + case infinitiViewer::SLICE_ORIENTATION_YZ: { double zVec = GetInput()->GetSpacing()[2]; - double upVal = (zVec > 0.0?1.0:-1.0); + double upVal = (zVec > 0.0 ? 1.0 : -1.0); cam->SetFocalPoint(0, 0, 0); - cam->SetPosition( -1 * upVal, 0, 0); // -1 if medical ? - cam->SetViewUp(0, 0, -1.0 *upVal); + cam->SetPosition(-1 * upVal, 0, 0); // -1 if medical ? + cam->SetViewUp(0, 0, -1.0 * upVal); break; } @@ -1272,235 +1224,93 @@ void infinitiViewer::UpdateOrientation() } } -void infinitiViewer::updateTopLeftCornerInfo() -{ - if (AnnoHelper::IsAnno()) { - int maxSlice = this->GetSliceMax(); - int currentSlice = this->GetSlice(); - std::string msg_const = m_cornerInfo.ConstAnno[TOP_LEFT]; - std::string msg_var = StatusMessage::Format(maxSlice, currentSlice); - std::string msg_upleft = StatusMessage::Format(msg_var, msg_const); - cornerAnnotation->SetText(TOP_LEFT, msg_upleft.c_str()); - } - this->Render(); -} - -void infinitiViewer::updateCornerInfo(int index) -{ - if (AnnoHelper::IsAnno()) { - - if (index == TOP_LEFT) - { - int maxSlice = this->GetSliceMax(); - int currentSlice = this->GetSlice(); - //cout << "MoveSliceForward::Slice = " << _Slice << std::endl; - std::string msg_const = m_cornerInfo.ConstAnno[index]; - std::string msg_var = StatusMessage::Format(currentSlice, maxSlice); - std::string msg_upleft = StatusMessage::Format(msg_var, msg_const); - //_StatusMapper->SetInput(msg.c_str()); - cornerAnnotation->SetText(index, msg_upleft.c_str()); - - } - - else if (index == BOTTOM_RIGHT) - { - std::string message = "WL/WW:"; - message += vtkVariant((int)this->GetColorLevel()).ToString(); - message += " / "; - message += vtkVariant((int)this->GetColorWindow()).ToString(); - - - cornerAnnotation->SetText(index, message.c_str()); - //m_renderWindowInteractor->Render(); - - //m_imageViewer->Modified(); - } - else if (index == TOP_RIGHT) - { - if (AnnoHelper::IsPrivacy()) - { - cornerAnnotation->SetText(index, m_cornerInfo.ConstAnno[TOP_RIGHT_PRIVACY].c_str()); - } - else - { - cornerAnnotation->SetText(index, m_cornerInfo.ConstAnno[index].c_str()); - } - - } - else - { - cornerAnnotation->SetText(index, m_cornerInfo.ConstAnno[index].c_str()); - } - } - this->Render(); -} - - -void infinitiViewer::initTopLeftCornerInfo(const std::string& lbl_ser_num, const std::string& ser_num) -{ - m_cornerInfo.ConstAnno[TOP_LEFT].append(lbl_ser_num); - m_cornerInfo.ConstAnno[TOP_LEFT].append(" "); - m_cornerInfo.ConstAnno[TOP_LEFT].append(ser_num); -} - -void infinitiViewer::initCornerInfo(ExtendMedicalImageProperties* pSeries) -{ - // mono and has preset - if (pSeries->GetNumberOfWindowLevelPresets() > 0 && pSeries->GetSamplePerPixel()==1) - { - double* wwwl = pSeries->GetNthWindowLevelPreset(0); - m_cornerInfo.win_level = (int)wwwl[1]; - m_cornerInfo.win_width = (int)wwwl[0]; - } - // no preset or color image - else{ - m_cornerInfo.win_level = 128; - m_cornerInfo.win_width = 256; - } - - char buffer[sizeof(long) * 8 + 1]; - const char* s = ltoa(pSeries->GetFileNames().size(), buffer, 10); - m_cornerInfo.ConstAnno[TOP_LEFT].clear(); - m_cornerInfo.ConstAnno[TOP_LEFT].append(buffer); - m_cornerInfo.ConstAnno[TOP_LEFT].append(" "); - m_cornerInfo.ConstAnno[TOP_LEFT].append(pSeries->GetSeriesNumber()); - - m_cornerInfo.ConstAnno[TOP_RIGHT].clear(); - m_cornerInfo.ConstAnno[TOP_RIGHT].append(pSeries->GetPatientName()); - m_cornerInfo.ConstAnno[TOP_RIGHT].append("\n"); - m_cornerInfo.ConstAnno[TOP_RIGHT].append(pSeries->GetStudyDescription()); - m_cornerInfo.ConstAnno[TOP_RIGHT].append("\n"); - m_cornerInfo.ConstAnno[TOP_RIGHT].append(pSeries->GetSeriesDescription()); - m_cornerInfo.ConstAnno[TOP_RIGHT].append("\n"); - m_cornerInfo.ConstAnno[TOP_RIGHT].append(pSeries->GetInstitutionName()); - m_cornerInfo.ConstAnno[TOP_RIGHT].append("\n"); - - m_cornerInfo.ConstAnno[TOP_RIGHT_PRIVACY].clear(); - m_cornerInfo.ConstAnno[TOP_RIGHT_PRIVACY].append("****"); - m_cornerInfo.ConstAnno[TOP_RIGHT_PRIVACY].append("\n"); - m_cornerInfo.ConstAnno[TOP_RIGHT_PRIVACY].append(pSeries->GetStudyDescription()); - m_cornerInfo.ConstAnno[TOP_RIGHT_PRIVACY].append("\n"); - m_cornerInfo.ConstAnno[TOP_RIGHT_PRIVACY].append(pSeries->GetSeriesDescription()); - m_cornerInfo.ConstAnno[TOP_RIGHT_PRIVACY].append("\n"); - m_cornerInfo.ConstAnno[TOP_RIGHT_PRIVACY].append("****"); - m_cornerInfo.ConstAnno[TOP_RIGHT_PRIVACY].append("\n"); - - double* d = pSeries->GetDirectionCosine(); - double xVector[3] = {d[0], d[1], d[2]}; - double yVector[3] = {d[3], d[4], d[5]}; - double zVector[3] = {0, 0, 0}; - vtkMath::Cross(xVector, yVector, zVector); - - - matrix->Zero(); - matrix->SetElement( 0,0, xVector[0]); - matrix->SetElement( 1,0, xVector[1]); - matrix->SetElement( 2,0, xVector[2]); - matrix->SetElement( 0,1, yVector[0]); - matrix->SetElement( 1,1, yVector[1]); - matrix->SetElement( 2,1, yVector[2]); - matrix->SetElement( 0,2, zVector[0]); - matrix->SetElement( 1,2, zVector[1]); - matrix->SetElement( 2,2, zVector[2]); - matrix->SetElement( 3,3, 1); -// matrix->Invert(); - - double* p = pSeries->GetPosition(); - imageDataOrigin[0] = p[0]; - imageDataOrigin[1] = p[1]; - imageDataOrigin[2] = p[2]; -} - -int getOrientationIndex(double* v){ +int getOrientationIndex(double *v) { int max_index = 0; - if (fabs(v[0])>fabs(v[1])){ - if (fabs(v[0])<=fabs(v[2])) max_index = 2; - } - else{ - if(fabs(v[1])>=fabs(v[2])) max_index=1; + if (fabs(v[0]) > fabs(v[1])) { + if (fabs(v[0]) <= fabs(v[2])) max_index = 2; + } else { + if (fabs(v[1]) >= fabs(v[2])) max_index = 1; else max_index = 2; } - return v[max_index]<0?max_index*2:2*max_index+1; + return v[max_index] < 0 ? max_index * 2 : 2 * max_index + 1; } -int getOppositeOrientation(int f){ +int getOppositeOrientation(int f) { int inner_idx = f % 2; return f + 1 - inner_idx * 2; } -void infinitiViewer::updateOrienInfo() -{ - static const char* dds[6] ={"R","L","A","P","F","H"}; - double proj[4] ={0,0,0,1}; +void infinitiViewer::UpdateOrientationInfo() { + static const char *dds[6] = {"R", "L", "A", "P", "F", "H"}; + double proj[4] = {0, 0, 0, 1}; Renderer->GetActiveCamera()->GetDirectionOfProjection(proj); - double viewUp[4]= {0,0,0,1}; + double viewUp[4] = {0, 0, 0, 1}; this->Renderer->GetActiveCamera()->GetViewUp(viewUp); double viewRight[4] = {0, 0, 0, 1}; - vtkMath::Cross(proj,viewUp, viewRight); + vtkMath::Cross(proj, viewUp, viewRight); - double viewUpVector[4]= {0,0,0,1}; - double viewRightVector[4]= {0,0,0,1}; + double viewUpVector[4] = {0, 0, 0, 1}; + double viewRightVector[4] = {0, 0, 0, 1}; //top and bottom matrix->MultiplyPoint(viewUp, viewUpVector); int flag = getOrientationIndex(viewUpVector); - viewUpIndex = flag; cornerAnnotation->SetText(TOP_MIDDLE, dds[flag]); cornerAnnotation->SetText(BOTTOM_MIDDLE, dds[getOppositeOrientation(flag)]); //left and right matrix->MultiplyPoint(viewRight, viewRightVector); flag = getOrientationIndex(viewRightVector); - viewRightIndex = flag; cornerAnnotation->SetText(RIGHT_MIDDLE, dds[flag]); cornerAnnotation->SetText(LEFT_MIDDLE, dds[getOppositeOrientation(flag)]); - cornerAnnotation->Modified(); -} - - -void infinitiViewer::updateCornerInfoAll() -{ - if (AnnoHelper::IsAnno()) { - updateCornerInfo(TOP_LEFT); - updateCornerInfo(BOTTOM_RIGHT); - updateCornerInfo(TOP_RIGHT); - - - updateCornerInfo(BOTTOM_MIDDLE); - updateCornerInfo(RIGHT_MIDDLE); - updateCornerInfo(LEFT_MIDDLE); - updateCornerInfo(TOP_MIDDLE); - } - else - { - cornerAnnotation->ClearAllTexts(); - this->Render(); - } -} - -void infinitiViewer::setUpImageViewer() -{ - this->SetColorLevel(m_cornerInfo.win_level); - this->SetColorWindow(m_cornerInfo.win_width); - //this->GetRenderer()->ResetCamera(); - this->SetSliceOrientationToXY(); - this->Render(); //first render will call resetcamera - this->SetSlice(0); - updateCornerInfoAll(); + cornerAnnotation->Modified(); } +// ruler legend---------------------------------------------------------------- void infinitiViewer::ActiveRuler() { - rulerActive = true; + rulerActive = true; } void infinitiViewer::UnActiveRuler() { - rulerActive = false; + rulerActive = false; } -int infinitiViewer::GetWorldSliceOrientation() { - double orientations[4]={.0, .0, .0, 1.0}; - orientations[SliceOrientation] = 1.0; - matrix->MultiplyPoint(orientations, orientations); - return (int)abs(round(1.0 * orientations[1]) + round(2.0 * orientations[2])); +void infinitiViewer::RenderRuler() { + if (AnnoHelper::IsAnno()) { + if (Renderer) { + ruler->RenderOverlay(Renderer); + } + } } +// size------------------------------------------------------------------------ +void infinitiViewer::SetSize(int width, int height) { + this->RenderWindow->SetSize(width, height); +} + +int *infinitiViewer::GetSize() { + return this->RenderWindow->GetSize(); +} + +//print self------------------------------------------------------------------- +void infinitiViewer::PrintSelf(ostream &os, vtkIndent indent) { + this->Superclass::PrintSelf(os, indent); + + os << indent << "RenderWindow:\n"; + this->RenderWindow->PrintSelf(os, indent.GetNextIndent()); + os << indent << "Renderer:\n"; + this->Renderer->PrintSelf(os, indent.GetNextIndent()); + os << indent << "ImageActor:\n"; + this->ImageActor->PrintSelf(os, indent.GetNextIndent()); + os << indent << "ImageMapper:\n" << endl; + this->ImageMapper->PrintSelf(os, indent.GetNextIndent()); + os << indent << "Slice: " << this->Slice << endl; + os << indent << "SliceOrientation: " << this->SliceOrientation << endl; + os << indent << "InteractorStyle: " << endl; + if (this->InteractorStyle) { + os << "\n"; + this->InteractorStyle->PrintSelf(os, indent.GetNextIndent()); + } else { + os << "None"; + } +} diff --git a/src/src/Rendering/infinitiViewer.h b/src/src/Rendering/infinitiViewer.h index 46bbcbb..15a9458 100644 --- a/src/src/Rendering/infinitiViewer.h +++ b/src/src/Rendering/infinitiViewer.h @@ -14,273 +14,324 @@ #include "Common/QGlobals.h" class vtkAlgorithm; + class vtkAlgorithmOutput; + class vtkImageStack; + class vtkImageSlice; + class vtkLookupTable; + class vtkScalarsToColors; + class vtkImageSliceMapper; + class vtkImageData; + class vtkInformation; + class ActorDraggableInteractorStyle; + class vtkRenderWindow; + class vtkRenderer; + class vtkRenderWindowInteractor; class ExtendMedicalImageProperties; + class MeasureStore; #define IN_TEST_MODE #ifdef IN_TEST_MODE + class vtkScalarBarActor; + #endif class vtkCornerAnnotation; + class Measure; -class infinitiViewer : public vtkObject -{ + +class infinitiViewer : public vtkObject { public: - static infinitiViewer* New(); - vtkTypeMacro(infinitiViewer, vtkObject); - void PrintSelf(ostream& os, vtkIndent indent) override; + static infinitiViewer *New(); - //vtkGetMacro(m_cornerAnnotation, vtkCornerAnnotation); - vtkCornerAnnotation* GetvtkCornerAnnotation() - { - return cornerAnnotation; - } - void updateCornerInfo(int index); - void updateCornerInfoAll(); - void initCornerInfo(ExtendMedicalImageProperties *pSeriesTags); - void updateOrienInfo(); - void setUpImageViewer(); +vtkTypeMacro(infinitiViewer, vtkObject); - //For Export - void initTopLeftCornerInfo(const std::string &lbl_ser_num, const std::string &SeriesNumber); - /** - * Get the name of rendering window. - */ - virtual const char* GetWindowName(); + void PrintSelf(ostream &os, vtkIndent indent) override; - /** - * Render the resulting image. - */ - virtual void Render(); + //vtkGetMacro(m_cornerAnnotation, vtkCornerAnnotation); + vtkCornerAnnotation *GetvtkCornerAnnotation() { + return cornerAnnotation; + } - //@{ - /** - * Set/Get the input image to the viewer. - */ - virtual void SetInputData(vtkImageData* in); - virtual vtkImageData* GetInput(); - virtual void SetInputConnection(vtkAlgorithmOutput* input); + void UpdateCornerInfo(int index); - //@} + void UpdateCornerInfoAll(); - /** - * Set/get the slice orientation - */ + void InitCornerInfo(ExtendMedicalImageProperties *pSeries); - enum - { - SLICE_ORIENTATION_YZ = 0, - SLICE_ORIENTATION_XZ = 1, - SLICE_ORIENTATION_XY = 2 - }; + void UpdateOrientationInfo(); - vtkGetMacro(SliceOrientation, int); - virtual void SetSliceOrientation(int orientation); + void SetupImageViewer(); - virtual void SetSliceOrientationToXY() - { - this->SetSliceOrientation(infinitiViewer::SLICE_ORIENTATION_XY); - } + //For Export + void InitTopLeftCornerInfo(const std::string &lbl_ser_num, const std::string &ser_num); - virtual void SetSliceOrientationToYZ() - { - this->SetSliceOrientation(infinitiViewer::SLICE_ORIENTATION_YZ); - } + /** + * Get the name of rendering window. + */ + virtual const char *GetWindowName(); + + /** + * Render the resulting image. + */ + virtual void Render(); + + //@{ + /** + * Set/Get the input image to the viewer. + */ + virtual void SetInputData(vtkImageData *in); + + virtual vtkImageData *GetInput(); + + virtual void SetInputConnection(vtkAlgorithmOutput *input); + + //@} + + /** + * Set/get the slice orientation + */ + + enum { + SLICE_ORIENTATION_YZ = 0, + SLICE_ORIENTATION_XZ = 1, + SLICE_ORIENTATION_XY = 2 + }; + + vtkGetMacro(SliceOrientation, int); + + virtual void SetSliceOrientation(int orientation); + + virtual void SetSliceOrientationToXY() { + this->SetSliceOrientation(infinitiViewer::SLICE_ORIENTATION_XY); + } + + virtual void SetSliceOrientationToYZ() { + this->SetSliceOrientation(infinitiViewer::SLICE_ORIENTATION_YZ); + } + + virtual void SetSliceOrientationToXZ() { + this->SetSliceOrientation(infinitiViewer::SLICE_ORIENTATION_XZ); + } - virtual void SetSliceOrientationToXZ() - { - this->SetSliceOrientation(infinitiViewer::SLICE_ORIENTATION_XZ); - } int GetWorldSliceOrientation(); - //@{ - /** - * Set/Get the current slice to display (depending on the orientation - * this can be in X, Y or Z). - */ - virtual int GetSlice(); - virtual void SetSlice(int s); - //@} + //@{ + /** + * Set/Get the current slice to display (depending on the orientation + * this can be in X, Y or Z). + */ + virtual int GetSlice(); - //@{ - /** - * Return the minimum and maximum slice values (depending on the orientation - * this can be in X, Y or Z). - */ - virtual int GetSliceMin(); - virtual int GetSliceMax(); - virtual void GetSliceRange(int range[2]) { this->GetSliceRange(range[0], range[1]); } - virtual void GetSliceRange(int& min, int& max); - virtual int* GetSliceRange(); - //@} + virtual void SetSlice(int s); + //@} - void ChangeSlice(vtkObject*,unsigned long eventid,void* calldata); - vtkSmartPointer GetSliceBoundPoints(); + //@{ + /** + * Return the minimum and maximum slice values (depending on the orientation + * this can be in X, Y or Z). + */ + virtual int GetSliceMin(); - //@{ - /** - * Set window and level for mapping pixels to colors. - */ - virtual double GetColorWindow(); - virtual double GetColorLevel(); - virtual void SetColorWindow(double s); - virtual void SetColorLevel(double s); - void SetNegativeMode(bool negative); - void SetLookupTable(vtkLookupTable *lut); - //@} + virtual int GetSliceMax(); - //@{ - /** - * These are here when using a Tk window. - */ - virtual void SetDisplayId(void* a); - virtual void SetWindowId(void* a); - virtual void SetParentId(void* a); - //@} + virtual void GetSliceRange(int range[2]) { this->GetSliceRange(range[0], range[1]); } - void SetZoomScale(double scale); - void SetPanOffset(const double* point); - void ResetZoomScaleToFitWindowSize(); - //@{ - /** - * Get the position (x and y) of the rendering window in - * screen coordinates (in pixels). - */ - virtual int* GetPosition() VTK_SIZEHINT(2); + virtual void GetSliceRange(int &min, int &max); - /** - * Set the position (x and y) of the rendering window in - * screen coordinates (in pixels). This resizes the operating - * system's view/window and redraws it. - */ - virtual void SetPosition(int x, int y); - virtual void SetPosition(int a[2]) { this->SetPosition(a[0], a[1]); } - //@} + virtual int *GetSliceRange(); + //@} - //@{ - /** - * Get the size (width and height) of the rendering window in - * screen coordinates (in pixels). - */ - virtual int* GetSize() VTK_SIZEHINT(2); + void ChangeSlice(vtkObject *, unsigned long eventid, void *calldata); - /** - * Set the size (width and height) of the rendering window in - * screen coordinates (in pixels). This resizes the operating - * system's view/window and redraws it. - * - * If the size has changed, this method will fire - * vtkCommand::WindowResizeEvent. - */ - virtual void SetSize(int width, int height); - virtual void SetSize(int a[2]) { this->SetSize(a[0], a[1]); } - //@} + vtkSmartPointer GetSliceBoundPoints(); - //@{ - /** - * Get the internal render window, renderer, image actor, and - * image map instances. - */ - vtkGetObjectMacro(RenderWindow, vtkRenderWindow); - vtkGetObjectMacro(Renderer, vtkRenderer); - vtkGetObjectMacro(ImageActor, vtkImageSlice); - vtkGetObjectMacro(ImageMapper, vtkImageSliceMapper); - vtkGetObjectMacro(InteractorStyle, ActorDraggableInteractorStyle); - //@} + //@{ + /** + * Set window and level for mapping pixels to colors. + */ + virtual double GetColorWindow(); - //@{ - /** - * Set your own renderwindow and renderer - */ - virtual void SetRenderWindow(vtkRenderWindow* arg); - virtual void SetRenderer(vtkRenderer* arg); - //@} + virtual double GetColorLevel(); - /** - * Attach an interactor for the internal render window. - */ - virtual void SetupInteractor(vtkRenderWindowInteractor*); + virtual void SetColorWindow(double s); - //@{ - /** - * Create a window in memory instead of on the screen. This may not - * be supported for every type of window and on some windows you may - * need to invoke this prior to the first render. - */ - virtual void SetOffScreenRendering(vtkTypeBool); - virtual vtkTypeBool GetOffScreenRendering(); - vtkBooleanMacro(OffScreenRendering, vtkTypeBool); - //@} + virtual void SetColorLevel(double s); + + void SetNegativeMode(bool negative); + + void SetLookupTable(vtkLookupTable *lut); + //@} + + //@{ + /** + * These are here when using a Tk window. + */ + virtual void SetDisplayId(void *a); + + virtual void SetWindowId(void *a); + + virtual void SetParentId(void *a); + //@} + + void SetZoomScale(double scale); + + void SetPanOffset(const double *point); + + void ResetZoomScaleToFitWindowSize(); + //@{ + /** + * Get the position (x and y) of the rendering window in + * screen coordinates (in pixels). + */ + virtual int *GetPosition() VTK_SIZEHINT(2); + + /** + * Set the position (x and y) of the rendering window in + * screen coordinates (in pixels). This resizes the operating + * system's view/window and redraws it. + */ + virtual void SetPosition(int x, int y); + + virtual void SetPosition(int a[2]) { this->SetPosition(a[0], a[1]); } + //@} + + //@{ + /** + * Get the size (width and height) of the rendering window in + * screen coordinates (in pixels). + */ + virtual int *GetSize() VTK_SIZEHINT(2); + + /** + * Set the size (width and height) of the rendering window in + * screen coordinates (in pixels). This resizes the operating + * system's view/window and redraws it. + * + * If the size has changed, this method will fire + * vtkCommand::WindowResizeEvent. + */ + virtual void SetSize(int width, int height); + + virtual void SetSize(int a[2]) { this->SetSize(a[0], a[1]); } + //@} + + //@{ + /** + * Get the internal render window, renderer, image actor, and + * image map instances. + */ + vtkGetObjectMacro(RenderWindow, vtkRenderWindow); + + vtkGetObjectMacro(Renderer, vtkRenderer); + + vtkGetObjectMacro(ImageActor, vtkImageSlice); + + vtkGetObjectMacro(ImageMapper, vtkImageSliceMapper); + + vtkGetObjectMacro(InteractorStyle, ActorDraggableInteractorStyle); + //@} + + //@{ + /** + * Set your own renderwindow and renderer + */ + virtual void SetRenderWindow(vtkRenderWindow *arg); + + virtual void SetRenderer(vtkRenderer *arg); + //@} + + /** + * Attach an interactor for the internal render window. + */ + virtual void SetupInteractor(vtkRenderWindowInteractor *); + + //@{ + /** + * Create a window in memory instead of on the screen. This may not + * be supported for every type of window and on some windows you may + * need to invoke this prior to the first render. + */ + virtual void SetOffScreenRendering(vtkTypeBool); + + virtual vtkTypeBool GetOffScreenRendering(); + + vtkBooleanMacro(OffScreenRendering, vtkTypeBool); + //@} - vtkGetMacro(Fusion, vtkTypeBool); - vtkSetMacro(Fusion, vtkTypeBool); - //@{ - /** - * Fusion On and Off,if fusion is on ,the renderer will try to show Fusion Data, - * which need to be set with SetFusionInputData function. Without SetFusionInputData, - * there will no Fusion Data show. - */ - vtkBooleanMacro(Fusion, vtkTypeBool); - //@} + vtkGetMacro(Fusion, vtkTypeBool); - //@{ - /** - * Fusion Opacity, default is 0.5 - */ - vtkGetMacro(FusionOpacity, double); - //@} - void SetFusionOpacity(double); - void IncreFusionOpacity(double); - void SetScalarBarTitle(double); - //@{ - /** - * Set a imageData to fusion with current rendered image. - */ - void SetFusionInputData(vtkImageData*); - //@} - - //@{ - /** - * Set color level for fusion lookupTable, only will take effect after SetFusionInputData. - */ - void SetFusionColorLeveL(double level); - //@} + vtkSetMacro(Fusion, vtkTypeBool); + //@{ + /** + * Fusion On and Off,if fusion is on ,the renderer will try to show Fusion Data, + * which need to be set with SetFusionInputData function. Without SetFusionInputData, + * there will no Fusion Data show. + */ + vtkBooleanMacro(Fusion, vtkTypeBool); + //@} - //@{ - /** - * Set color window for fusion lookupTable, only will take effect after SetFusionInputData. - */ - void SetFusionColorWindow(double window); - //@} + //@{ + /** + * Fusion Opacity, default is 0.5 + */ + vtkGetMacro(FusionOpacity, double); - //@{ - /** - * Set a ColorTable for fusion, only will take effect after SetFusionInputData. - */ - void SetFusionColorTable(vtkScalarsToColors*); + //@} + void SetFusionOpacity(double); + + void IncreFusionOpacity(double); + + void SetScalarBarTitle(double); + //@{ + /** + * Set a imageData to fusion with current rendered image. + */ + void SetFusionInputData(vtkImageData *); + //@} + + //@{ + /** + * Set color level for fusion lookupTable, only will take effect after SetFusionInputData. + */ + void SetFusionColorLeveL(double level); + //@} + + //@{ + /** + * Set color window for fusion lookupTable, only will take effect after SetFusionInputData. + */ + void SetFusionColorWindow(double window); + //@} + + //@{ + /** + * Set a ColorTable for fusion, only will take effect after SetFusionInputData. + */ + void SetFusionColorTable(vtkScalarsToColors *); //@} //@{ /** * Set a Preset ColorTable for fusion, only will take effect after SetFusionInputData. */ void SetFusionColorPreset(const char *preset); - //@} + //@} //@} //@{ /** @@ -288,109 +339,123 @@ public: */ void SwitchToNextPreset(); //@} - // - //@{ - /** - * Remove fusion from viewer - */ - void RemoveFusionData(); - //@} + // + //@{ + /** + * Remove fusion from viewer + */ + void RemoveFusionData(); + //@} - //@{ - /** - * Remove fusion actor from viewer - */ - void RemoveFusionActor(); + //@{ + /** + * Remove fusion actor from viewer + */ + void RemoveFusionActor(); void DeleteSelectedMeasure(); + void DeleteCurrentSliceMeasure(); + void DeleteCurrentSeriesMeasure(); - void ActiveMeasure(Measure* m); - void UnActiveMeasure(); + void ActiveMeasure(Measure *m); + + void UnActiveMeasure(); void ActiveRuler(); + void UnActiveRuler(); - //for convert vtkEvent to Qt signal - vtkSignalRaiser* GetSignalRaiser(){ + //for convert vtkEvent to Qt signal + vtkSignalRaiser *GetSignalRaiser() { return &raiser; } - void SyncSlicePoint(double* point); - void GetSlicePoint(double* point); + + void SyncSlicePoint(double *point); + + void GetSlicePoint(double *point); protected: - infinitiViewer(); - ~infinitiViewer() override; + infinitiViewer(); + + ~infinitiViewer() override; + + vtkAlgorithm *GetInputAlgorithm(); + + vtkInformation *GetInputInformation(); virtual void InstallPipeline(); - virtual void UnInstallPipeline(); - void PrepareFusionColorTable(vtkScalarsToColors* table, bool reset = false); + virtual void UnInstallPipeline(); - vtkRenderWindow* RenderWindow; - vtkRenderer* Renderer; - vtkImageStack* ImageStack; - vtkImageSlice* ImageActor; - vtkImageSlice* FusionActor; - vtkImageSliceMapper* ImageMapper; - vtkImageSliceMapper* FusionMapper; - vtkRenderWindowInteractor* Interactor; - ActorDraggableInteractorStyle* InteractorStyle = nullptr; - vtkTextActor* OpacityActor; - vtkCornerAnnotation* cornerAnnotation; + void PrepareFusionColorTable(vtkScalarsToColors *table, bool reset = false); - #ifdef IN_TEST_MODE - vtkScalarBarActor* bar; - #endif + virtual void UpdateOrientation(); - int SliceOrientation; - int FirstRender; - int Slice; - int loadedMeasureSlice; - - vtkTypeBool Fusion = false; - vtkTypeBool firstFusion = true; - double FusionOpacity = 0.5; - - - virtual void UpdateOrientation(); - vtkAlgorithm* GetInputAlgorithm(); - vtkInformation* GetInputInformation(); - void LoadMeasures(){ + void LoadMeasures() { LoadMeasures(false); - } - void LoadMeasures(bool forceReload); - void AddMeasures(vtkObject*,unsigned long eventid,void* calldata ); - void RemoveMeasures(vtkObject*,unsigned long eventid,void* calldata ); + } + + void LoadMeasures(bool forceReload); + + void AddMeasures(vtkObject *, unsigned long eventid, void *calldata); + + void RemoveMeasures(vtkObject *, unsigned long eventid, void *calldata); private: - infinitiViewer(const infinitiViewer&) = delete; - void operator=(const infinitiViewer&) = delete; - std::vector> fusion_tf_vector; + infinitiViewer(const infinitiViewer &) = delete; + + void operator=(const infinitiViewer &) = delete; + + std::vector> fusion_tf_vector; //for convert vtkEvent to Qt signal vtkSignalRaiser raiser; - QList* list = nullptr; - MeasureStore* measureStore; + QList *list = nullptr; + MeasureStore *measureStore; - void raiseEvent(vtkObject* sender,unsigned long eventId,void* callData = nullptr){ - raiser.raiseEvent(sender,eventId,callData); + void raiseEvent(vtkObject *sender, unsigned long eventId, void *callData = nullptr) { + raiser.raiseEvent(sender, eventId, callData); } + void ClearCurrentSliceMeasure() const; + void ReloadCurrentSliceMeasure(); - void updateTopLeftCornerInfo(); + + void UpdateTopLeftCornerInfo(); + + void RenderRuler(); + + vtkRenderWindow *RenderWindow; + vtkRenderer *Renderer; + vtkImageStack *ImageStack; + vtkImageSlice *ImageActor; + vtkImageSlice *FusionActor; + vtkImageSliceMapper *ImageMapper; + vtkImageSliceMapper *FusionMapper; + vtkRenderWindowInteractor *Interactor; + ActorDraggableInteractorStyle *InteractorStyle = nullptr; + vtkTextActor *OpacityActor; + vtkCornerAnnotation *cornerAnnotation; + vtkScalarBarActor *bar; vtkNew ruler; - bool rulerActive = false; - void RenderRuler(); - int currentPresetIndex=1; - int viewUpIndex = 0; - int viewRightIndex = 1; - DicomCornerInfo m_cornerInfo; - char SOP_UID[20]={0}; - double imageDataOrigin[3] = {.0, .0, .0}; vtkNew matrix; + DicomCornerInfo m_cornerInfo; + + int SliceOrientation; + int FirstRender; + int Slice; + int loadedMeasureSlice; + int currentPresetIndex = 1; + vtkTypeBool Fusion = false; + vtkTypeBool firstFusion = true; + + double FusionOpacity = 0.5; + bool rulerActive = false; + char SOP_UID[20] = {0}; + double imageDataOrigin[3] = {.0, .0, .0}; }; #endif diff --git a/src/src/UI/Widget/dicomimageview.cpp b/src/src/UI/Widget/dicomimageview.cpp index 6e3355d..6c5bd21 100644 --- a/src/src/UI/Widget/dicomimageview.cpp +++ b/src/src/UI/Widget/dicomimageview.cpp @@ -128,7 +128,7 @@ void DicomImageView::Slot_WindowLevelEventForFusion(double level, double width) void DicomImageView::Slot_Transformation() { - mImageViewer->updateOrienInfo(); + mImageViewer->UpdateOrientationInfo(); mImageViewer->Render(); } @@ -331,9 +331,9 @@ void DicomImageView::LoadSeries(SeriesImageSet *series) { mSeries = series; mImageViewer->SetInputData(mSeries->GetData()); - mImageViewer->initCornerInfo(series->GetProperty()); - mImageViewer->setUpImageViewer(); - mImageViewer->updateOrienInfo(); + mImageViewer->InitCornerInfo(series->GetProperty()); + mImageViewer->SetupImageViewer(); + mImageViewer->UpdateOrientationInfo(); //以下是一些转接函数 //使用connect 替代 AddObserver,避免出现多种事件机制架构 connect(mImageViewer->GetSignalRaiser(),&vtkSignalRaiser::raiseEvent, this, &DicomImageView::syncEventFunc); @@ -350,7 +350,7 @@ void DicomImageView::LoadSeries(SeriesImageSet *series) //Callbacks------------------------------------------------------------------------------------ void DicomImageView::updateWindowLevelCb(vtkObject* caller, unsigned long eid, void *calldata) { - mImageViewer->updateCornerInfo(BOTTOM_RIGHT); + mImageViewer->UpdateCornerInfo(BOTTOM_RIGHT); emit Signal_WindowLevelEventForFusion(mImageViewer->GetColorLevel(), mImageViewer->GetColorWindow()); } @@ -538,7 +538,7 @@ void DicomImageView::SetWindowLevel(double level, double width) mImageViewer->SetColorWindow(width); //You have to call updateConerInfo manually //only mouse event can rely on callback - mImageViewer->updateCornerInfo(BOTTOM_RIGHT); + mImageViewer->UpdateCornerInfo(BOTTOM_RIGHT); emit Signal_WindowLevelEventForFusion(level, width); } @@ -652,7 +652,7 @@ void DicomImageView::updateCornerInfoAll() { if (HasSeries()) { - mImageViewer->updateCornerInfoAll(); + mImageViewer->UpdateCornerInfoAll(); } } @@ -660,7 +660,7 @@ void DicomImageView::updateCornerInfoPrivacy() { if (HasSeries()) { - mImageViewer->updateCornerInfo(TOP_RIGHT); + mImageViewer->UpdateCornerInfo(TOP_RIGHT); } } @@ -802,8 +802,5 @@ void DicomImageView::viewerClicked() { } void DicomImageView::SyncScrollBar() { -// setScrollChangedType(scrollScope::TriggerType::SYNC_ONLY); mScrollBar->SetValueSilently(mImageViewer->GetSlice()); - mImageViewer->updateCornerInfo(TOP_LEFT); -// setScrollChangedType(scrollScope::TriggerType::USER_TRIGGER); } diff --git a/src/src/UI/Window/QDicomViewer.cpp b/src/src/UI/Window/QDicomViewer.cpp index 1ff493c..e498480 100644 --- a/src/src/UI/Window/QDicomViewer.cpp +++ b/src/src/UI/Window/QDicomViewer.cpp @@ -594,7 +594,6 @@ void QDicomViewer::SetupFlipTool(QToolButton* flipBtn) if (curV != nullptr && curV->HasSeries()) { curV->Rotate(90, ROTATE_90_CCW); - //curV->getImageViewer()->updateOrienInfo(); } }); @@ -603,7 +602,6 @@ void QDicomViewer::SetupFlipTool(QToolButton* flipBtn) if (curV != nullptr && curV->HasSeries()) { curV->Rotate(-90, ROTATE_90_CW); - //curV->getImageViewer()->updateOrienInfo(); } }); m->addAction(tr("Rotate 180"), this, [&] { @@ -611,7 +609,6 @@ void QDicomViewer::SetupFlipTool(QToolButton* flipBtn) if (curV != nullptr && curV->HasSeries()) { curV->Rotate(180, ROTATE_180); - //curV->getImageViewer()->updateOrienInfo(); } }); @@ -621,7 +618,6 @@ void QDicomViewer::SetupFlipTool(QToolButton* flipBtn) if (curV != nullptr && curV->HasSeries()) { curV->HFlip(); - //curV->getImageViewer()->updateOrienInfo(H_FLIP); } }); m->addAction(tr("Flip vertical"), this, [&] { @@ -629,7 +625,6 @@ void QDicomViewer::SetupFlipTool(QToolButton* flipBtn) if (curV != nullptr && curV->HasSeries()) { curV->VFlip(); - //curV->getImageViewer()->updateOrienInfo(V_FLIP); } }); @@ -639,7 +634,6 @@ void QDicomViewer::SetupFlipTool(QToolButton* flipBtn) if (curV != nullptr && curV->HasSeries()) { curV->ClearTransformations(); - //curV->getImageViewer()->updateOrienInfo(CLEAR); } }); flipBtn->setPopupMode(QToolButton::MenuButtonPopup); @@ -650,7 +644,6 @@ void QDicomViewer::SetupFlipTool(QToolButton* flipBtn) if (curV != nullptr && curV->HasSeries()) { curV->Rotate(90, ROTATE_90_CCW); - //curV->getImageViewer()->updateOrienInfo(ROTATE_90_CCW); } }); }