Skip to content

Commit

Permalink
ENH: Add support for adjusting Magnification
Browse files Browse the repository at this point in the history
Adapted from KitwareMedical/SlicerVirtualReality@a8f3d8674
(ENH: Make magnification (formerly physical scale) slider functional)

Note that since the magnification is independent from widget event handling,
the vtkMixedRealityViewInteractorStyle still derives from vtkOpenXRInteractorStyle.

Co-authored-by: Csaba Pinter <[email protected]>
  • Loading branch information
jcfr and cpinter committed Aug 28, 2023
1 parent f31ada6 commit fa3d863
Show file tree
Hide file tree
Showing 13 changed files with 563 additions and 35 deletions.
8 changes: 8 additions & 0 deletions MixedReality/MRML/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ project(vtkSlicer${MODULE_NAME}ModuleMRML)

set(KIT ${PROJECT_NAME})

#-----------------------------------------------------------------------------
find_package(vtkRenderingOpenXR REQUIRED)

#-----------------------------------------------------------------------------
set(${KIT}_EXPORT_DIRECTIVE "VTK_SLICER_${MODULE_NAME_UPPER}_MODULE_MRML_EXPORT")

Expand All @@ -16,11 +19,16 @@ set(${KIT}_SRCS
vtkMRML${MODULE_NAME}ViewNode.h
# vtkMRML${MODULE_NAME}LayoutNode.cxx
# vtkMRML${MODULE_NAME}LayoutNode.h
vtk${MODULE_NAME}ViewInteractor.cxx
vtk${MODULE_NAME}ViewInteractor.h
vtk${MODULE_NAME}ViewInteractorStyle.cxx
vtk${MODULE_NAME}ViewInteractorStyle.h
)

set(${KIT}_TARGET_LIBRARIES
${VTK_LIBRARIES}
${MRML_LIBRARIES}
VTK::RenderingOpenXR
)

#-----------------------------------------------------------------------------
Expand Down
9 changes: 9 additions & 0 deletions MixedReality/MRML/vtkMRMLMixedRealityViewNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,23 @@ class VTK_SLICER_MIXEDREALITY_MODULE_MRML_EXPORT vtkMRMLMixedRealityViewNode
vtkSetMacro(PlayerIPAddress, const std::string);
vtkGetMacro(PlayerIPAddress, std::string);

/// Magnification of world [0.01, 100].
/// Value greater than 1 means that objects appear larger in VR than their real world size.
/// Translated to physical scale of the VR render window
vtkGetMacro(Magnification, double);
vtkSetMacro(Magnification, double);

protected:
vtkMRMLMixedRealityViewNode();
~vtkMRMLMixedRealityViewNode() override;
vtkMRMLMixedRealityViewNode(const vtkMRMLMixedRealityViewNode&);
void operator=(const vtkMRMLMixedRealityViewNode&);

// Connection
std::string PlayerIPAddress;

// Display
double Magnification;
static const char* ReferenceViewNodeReferenceRole;
};

Expand Down
38 changes: 38 additions & 0 deletions MixedReality/MRML/vtkMixedRealityViewInteractor.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*==============================================================================
Copyright (c) Laboratory for Percutaneous Surgery (PerkLab)
Queen's University, Kingston, ON, Canada. All Rights Reserved.
See COPYRIGHT.txt
or http://www.slicer.org/copyright/copyright.txt for details.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
This file was originally developed by Csaba Pinter, PerkLab, Queen's University
and was supported through CANARIE's Research Software Program, and Cancer
Care Ontario.
==============================================================================*/

#include "vtkMixedRealityViewInteractor.h"

// VTK includes
#include <vtkObjectFactory.h>

// SlicerMixedReality includes
#include "vtkMixedRealityViewInteractorStyle.h"

vtkStandardNewMacro(vtkMixedRealityViewInteractor);

vtkMixedRealityViewInteractor::vtkMixedRealityViewInteractor() = default;
vtkMixedRealityViewInteractor::~vtkMixedRealityViewInteractor() = default;

//----------------------------------------------------------------------------
void vtkMixedRealityViewInteractor::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
}
55 changes: 55 additions & 0 deletions MixedReality/MRML/vtkMixedRealityViewInteractor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*==============================================================================
Copyright (c) Laboratory for Percutaneous Surgery (PerkLab)
Queen's University, Kingston, ON, Canada. All Rights Reserved.
See COPYRIGHT.txt
or http://www.slicer.org/copyright/copyright.txt for details.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
This file was originally developed by Csaba Pinter, PerkLab, Queen's University
and was supported through CANARIE's Research Software Program, and Cancer
Care Ontario.
==============================================================================*/

#ifndef vtkMixedRealityViewInteractor_h
#define vtkMixedRealityViewInteractor_h

#include "vtkSlicerMixedRealityModuleMRMLExport.h"

#include <vtkOpenXRRenderWindowInteractor.h>

#include <vector>

// vtkRenderingOpenXR is not python wrapped, so wrapping New causes linking error //TODO:
#ifndef __VTK_WRAP__

class VTK_SLICER_MIXEDREALITY_MODULE_MRML_EXPORT vtkMixedRealityViewInteractor : public vtkOpenXRRenderWindowInteractor
{
public:
static vtkMixedRealityViewInteractor *New();

typedef vtkMixedRealityViewInteractor Self;

vtkTypeMacro(vtkMixedRealityViewInteractor,vtkOpenXRRenderWindowInteractor);
void PrintSelf(ostream& os, vtkIndent indent) override;

protected:

private:
vtkMixedRealityViewInteractor();
~vtkMixedRealityViewInteractor() override;

vtkMixedRealityViewInteractor(const vtkMixedRealityViewInteractor&) = delete;
void operator=(const vtkMixedRealityViewInteractor&) = delete;
};

#endif // __VTK_WRAP__

#endif
196 changes: 196 additions & 0 deletions MixedReality/MRML/vtkMixedRealityViewInteractorStyle.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
/*==============================================================================
Copyright (c) Laboratory for Percutaneous Surgery (PerkLab)
Queen's University, Kingston, ON, Canada. All Rights Reserved.
See COPYRIGHT.txt
or http://www.slicer.org/copyright/copyright.txt for details.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
This file was originally developed by Csaba Pinter, PerkLab, Queen's University
and was supported through CANARIE's Research Software Program, and Cancer
Care Ontario.
==============================================================================*/

#include "vtkMixedRealityViewInteractorStyle.h"

// VR MRML includes
//#include "vtkMRMLMixedRealityViewNode.h"

// MRML includes
//#include "vtkMRMLAbstractThreeDViewDisplayableManager.h"
//#include "vtkMRMLDisplayableManagerGroup.h"
//#include "vtkMRMLScene.h"

// VTK includes
#include <vtkCamera.h>
#include <vtkCellPicker.h>
#include <vtkCallbackCommand.h>
#include <vtkMath.h>
#include <vtkObjectFactory.h>
#include <vtkPoints.h>
#include <vtkRenderer.h>
#include <vtkQuaternion.h>
#include <vtkTimerLog.h>
#include <vtkTransform.h>
#include <vtkWeakPointer.h>
#include <vtkWorldPointPicker.h>

// VTK OpenXR
#include <vtkOpenXRRenderWindow.h>
#include <vtkOpenXRRenderWindowInteractor.h>


vtkStandardNewMacro(vtkMixedRealityViewInteractorStyle);

//----------------------------------------------------------------------------
class vtkMixedRealityViewInteractorStyle::vtkInternal
{
public:
vtkInternal() = default;
~vtkInternal() = default;
public:
};

//---------------------------------------------------------------------------
// vtkMixedRealityViewInteractorStyle methods

//----------------------------------------------------------------------------
vtkMixedRealityViewInteractorStyle::vtkMixedRealityViewInteractorStyle()
{
this->Internal = new vtkInternal();
}

//----------------------------------------------------------------------------
vtkMixedRealityViewInteractorStyle::~vtkMixedRealityViewInteractorStyle()
{
delete this->Internal;
}

//----------------------------------------------------------------------------
void vtkMixedRealityViewInteractorStyle::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
}

//----------------------------------------------------------------------------
// Generic events binding
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
// Interaction methods
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
// Interaction entry points
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
// Multitouch interaction methods
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
// Utility routines
//----------------------------------------------------------------------------

//---------------------------------------------------------------------------
//vtkMRMLScene* vtkMixedRealityViewInteractorStyle::GetMRMLScene()
//{
// if (!this->DisplayableManagers
// || this->DisplayableManagers->GetDisplayableManagerCount() == 0)
// {
// return nullptr;
// }

// return this->DisplayableManagers->GetNthDisplayableManager(0)->GetMRMLScene();
//}

//---------------------------------------------------------------------------
void vtkMixedRealityViewInteractorStyle::SetMagnification(double magnification)
{
if (this->CurrentRenderer == nullptr)
{
return;
}

vtkOpenXRRenderWindowInteractor* rwi = static_cast<vtkOpenXRRenderWindowInteractor*>(this->Interactor);
vtkOpenXRRenderWindow* rw = static_cast<vtkOpenXRRenderWindow*>(rwi->GetRenderWindow());

double currentPhysicalScale = rw->GetPhysicalScale();
double newPhysicalScale = 1000.0 / magnification;
double scaleFactor = newPhysicalScale / currentPhysicalScale;
if (fabs(scaleFactor - 1.0) < 0.001)
{
return;
}

// Get Physical to World_Origin matrix
vtkNew<vtkMatrix4x4> physicalToWorldOriginMatrix;
rw->GetPhysicalToWorldMatrix(physicalToWorldOriginMatrix);

// Calculate World_Origin to World_FocusPoint matrix
double bounds[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
this->CurrentRenderer->ComputeVisiblePropBounds(bounds);
double focusPoint_World[3] = { (bounds[1] + bounds[0]) / 2.0,
(bounds[3] + bounds[2]) / 2.0,
(bounds[5] + bounds[4]) / 2.0 };
vtkNew<vtkMatrix4x4> worldOriginToWorldFocusPointMatrix;
for (int i=0; i<3; ++i)
{
worldOriginToWorldFocusPointMatrix->SetElement(i,3, -focusPoint_World[i]);
}

// Calculate World_FocusPoint to World_ScaledFocusPoint matrix
vtkNew<vtkMatrix4x4> worldFocusPointToWorldScaledFocusPointMatrix;
for (int i=0; i<3; ++i)
{
worldFocusPointToWorldScaledFocusPointMatrix->SetElement(i,i, scaleFactor);
}

// Calculate World_ScaledFocusPoint to World_ScaledOrigin matrix
vtkNew<vtkMatrix4x4> worldScaledFocusPointToWorldScaledOriginMatrix;
for (int i=0; i<3; ++i)
{
worldScaledFocusPointToWorldScaledOriginMatrix->SetElement(i,3, focusPoint_World[i]);
}

// Calculate Physical to World_ScaledOrigin matrix
vtkNew<vtkMatrix4x4> worldFocusPointToWorldScaledOriginMatrix;
vtkMatrix4x4::Multiply4x4( worldScaledFocusPointToWorldScaledOriginMatrix, worldFocusPointToWorldScaledFocusPointMatrix,
worldFocusPointToWorldScaledOriginMatrix );

vtkNew<vtkMatrix4x4> worldOriginToWorldScaledOriginMatrix;
vtkMatrix4x4::Multiply4x4( worldFocusPointToWorldScaledOriginMatrix, worldOriginToWorldFocusPointMatrix,
worldOriginToWorldScaledOriginMatrix );

// Physical to World_ScaledOrigin
vtkNew<vtkMatrix4x4> physicalToWorldScaledOriginMatrix;
vtkMatrix4x4::Multiply4x4( worldOriginToWorldScaledOriginMatrix, physicalToWorldOriginMatrix,
physicalToWorldScaledOriginMatrix );

rw->SetPhysicalToWorldMatrix(physicalToWorldScaledOriginMatrix);

if (this->AutoAdjustCameraClippingRange)
{
this->CurrentRenderer->ResetCameraClippingRange();
}
if (this->Interactor->GetLightFollowCamera())
{
this->CurrentRenderer->UpdateLightsGeometryToFollowCamera();
}
}

//---------------------------------------------------------------------------
double vtkMixedRealityViewInteractorStyle::GetMagnification()
{
vtkOpenXRRenderWindowInteractor* rwi = static_cast<vtkOpenXRRenderWindowInteractor*>(this->Interactor);
vtkOpenXRRenderWindow* rw = static_cast<vtkOpenXRRenderWindow*>(rwi->GetRenderWindow());

return 1000.0 / rw->GetPhysicalScale();
}
Loading

0 comments on commit fa3d863

Please sign in to comment.