Skip to content
Draft
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions library/options.json
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,16 @@
"invert_zoom": {
"type": "bool",
"default_value": "false"
},
"axis_lock": {
"axis": {
"type": "direction",
"default_value": "0,0,0"
},
"enabled": {
"type": "bool",
"default_value": "false"
}
}
}
}
22 changes: 22 additions & 0 deletions library/src/interactor_impl.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,22 @@ interactor& interactor_impl::initCommands()
this->Internals->Window.PrintColoringDescription(log::VerboseLevel::DEBUG);
});

this->addCommand("toggle_axis_lock",
[&](const std::vector<std::string>& args)
{
check_args(args, 1, "toggle_axis_lock");
const std::string val{ this->Internals->Options.getAsString("interactor.axis_lock.axis") };
if (args[0] == val && this->Internals->Options.interactor.axis_lock.enabled)
{
this->Internals->Options.interactor.axis_lock.enabled = false;
}
else
{
this->Internals->Options.interactor.axis_lock.axis = options::parse<f3d::direction_t>(args[0]);
this->Internals->Options.interactor.axis_lock.enabled = true;
}
});

this->addCommand("roll_camera",
[&](const std::vector<std::string>& args)
{
Expand Down Expand Up @@ -1178,6 +1194,9 @@ interactor& interactor_impl::initBindings()
"Cycle verbose level", this->Internals->VerboseLevelToString(log::getVerboseLevel()));
};

auto docAxisTgl = [&](const std::string& doc, const std::string& val)
{ return std::pair(doc, (this->Internals->Options.interactor.axis_lock.enabled && val == this->Internals->Options.getAsString("interactor.axis_lock.axis") ? "ON" : "OFF")); };

// clang-format off
this->addBinding({mod_t::NONE, "W"}, "cycle_animation", "Scene", docAnim);
this->addBinding({mod_t::NONE, "C"}, "cycle_coloring field", "Scene", docField);
Expand Down Expand Up @@ -1206,6 +1225,9 @@ interactor& interactor_impl::initBindings()
this->addBinding({mod_t::NONE, "O"}, "toggle model.point_sprites.enable","Scene", std::bind(docTgl, "Toggle point sprites rendering", std::cref(opts.model.point_sprites.enable)));
this->addBinding({mod_t::NONE, "U"}, "toggle render.background.blur.enable","Scene", std::bind(docTgl, "Toggle blur background", std::cref(opts.render.background.blur.enable)));
this->addBinding({mod_t::NONE, "K"}, "toggle interactor.trackball","Scene", std::bind(docTgl, "Toggle trackball interaction", std::cref(opts.interactor.trackball)));
this->addBinding({mod_t::CTRL, "X"}, "toggle_axis_lock +X", "Scene", [=]() { return docAxisTgl("Toggle x axis lock", "+X"); });
this->addBinding({mod_t::CTRL, "Y"}, "toggle_axis_lock +Y", "Scene", [=]() { return docAxisTgl("Toggle y axis lock", "+Y"); });
this->addBinding({mod_t::CTRL, "Z"}, "toggle_axis_lock +Z", "Scene", [=]() { return docAxisTgl("Toggle z axis lock", "+Z"); });
this->addBinding({mod_t::NONE, "F"}, "toggle render.hdri.ambient","Scene", std::bind(docTgl, "Toggle HDRI ambient lighting", std::cref(opts.render.hdri.ambient)));
this->addBinding({mod_t::NONE, "J"}, "toggle render.background.skybox","Scene", std::bind(docTgl, "Toggle HDRI skybox", std::cref(opts.render.background.skybox)));
this->addBinding({mod_t::NONE, "L"}, "increase_light_intensity", "Scene", std::bind(docDbl, "Increase lights intensity", std::cref(opts.render.light.intensity)));
Expand Down
1 change: 1 addition & 0 deletions library/src/window_impl.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@ void window_impl::UpdateDynamicOptions()
renderer->ShowAxis(opt.ui.axis);
renderer->SetUseTrackball(opt.interactor.trackball);
renderer->SetInvertZoom(opt.interactor.invert_zoom);
renderer->SetRotationAxis(opt.interactor.axis_lock.enabled, opt.interactor.axis_lock.axis);
}

// XXX: model.point_sprites.type only has an effect on geometry scene
Expand Down
52 changes: 37 additions & 15 deletions vtkext/private/module/vtkF3DInteractorStyle.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -169,23 +169,45 @@ void vtkF3DInteractorStyle::Rotate()
this->InterpolateTemporaryUp(0.1, ren->GetUpVector(), up);
}

// Rotate camera around the focal point about the environment's up vector
vtkNew<vtkTransform> Transform;
Transform->Identity();
const double* fp = camera->GetFocalPoint();
Transform->Translate(+fp[0], +fp[1], +fp[2]);
Transform->RotateWXYZ(rxf, ren->GetUpVector());
Transform->Translate(-fp[0], -fp[1], -fp[2]);
Transform->TransformPoint(camera->GetPosition(), camera->GetPosition());

camera->SetViewUp(up);

// Clamp parameter to `camera->Elevation()` to maintain -90 < elevation < +90
constexpr double maxAbsElevation = 90 - 1e-10;
const double elevation = vtkMath::DegreesFromRadians(
vtkMath::AngleBetweenVectors(ren->GetUpVector(), camera->GetDirectionOfProjection()) -
vtkMath::Pi() / 2);
camera->Elevation(std::clamp(ryf, -maxAbsElevation - elevation, +maxAbsElevation - elevation));
double newPos[3];
if (ren->GetUseRotationAxis())
{
Transform->Identity();
Transform->Translate(+fp[0], +fp[1], +fp[2]);
Transform->RotateWXYZ(ren->GetMovementVector()[0] * rxf + ren->GetMovementVector()[1] * ryf,
ren->GetRotationAxis());
Transform->Translate(-fp[0], -fp[1], -fp[2]);

Transform->TransformPoint(camera->GetPosition(), newPos);
camera->SetPosition(newPos);

double newViewUp[3];
Transform->TransformVector(camera->GetViewUp(), newViewUp);
camera->SetViewUp(newViewUp);
}
else
{
// Rotate camera around the focal point about the environment's up vector
Transform->Identity();
Transform->Translate(+fp[0], +fp[1], +fp[2]);
Transform->RotateWXYZ(rxf, ren->GetUpVector());
Transform->Translate(-fp[0], -fp[1], -fp[2]);

Transform->TransformPoint(camera->GetPosition(), newPos);
camera->SetPosition(newPos);

// Clamp parameter to `camera->Elevation()` to maintain -90 < elevation < +90
constexpr double maxAbsElevation = 90 - 1e-10;
const double elevation = vtkMath::DegreesFromRadians(
vtkMath::AngleBetweenVectors(ren->GetUpVector(), camera->GetDirectionOfProjection()) -
vtkMath::Pi() / 2);
camera->Elevation(
std::clamp(ryf, -maxAbsElevation - elevation, +maxAbsElevation - elevation));

camera->SetViewUp(up);
}

camera->OrthogonalizeViewUp();
}
Expand Down
19 changes: 19 additions & 0 deletions vtkext/private/module/vtkF3DRenderer.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -1734,6 +1734,25 @@ void vtkF3DRenderer::SetUseTrackball(bool use)
}
}

//----------------------------------------------------------------------------
void vtkF3DRenderer::SetRotationAxis(bool use, const std::vector<double>& axis)
{
std::array<double, 3> prev = { this->RotationAxis[0], this->RotationAxis[1],
this->RotationAxis[2] };
std::array<double, 3> curr = { axis[0], axis[1], axis[2] };

if (use != this->UseRotationAxis || curr != prev)
{
this->UseRotationAxis = use;

this->RotationAxis[0] = axis[0];
this->RotationAxis[1] = axis[1];
this->RotationAxis[2] = axis[2];

this->CheatSheetConfigured = false;
}
}

//----------------------------------------------------------------------------
void vtkF3DRenderer::UpdateActors()
{
Expand Down
11 changes: 11 additions & 0 deletions vtkext/private/module/vtkF3DRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,14 @@ class vtkF3DRenderer : public vtkOpenGLRenderer
///@}

/**
* Set/Get RotationAxis
*/
void SetRotationAxis(bool use, const std::vector<double>& axis);
vtkGetMacro(UseRotationAxis, bool);
vtkGetVector3Macro(RotationAxis, double);
vtkGetVector2Macro(MovementVector, double);

/**
* Reimplemented to configure:
* - ActorsProperties
* - Timer
Expand Down Expand Up @@ -579,6 +587,9 @@ class vtkF3DRenderer : public vtkOpenGLRenderer
std::optional<bool> UseOrthographicProjection = false;
bool UseTrackball = false;
bool InvertZoom = false;
bool UseRotationAxis = false;
double RotationAxis[3] = { 0.0, 0.0, 0.0 };
Comment on lines +605 to +606
Copy link
Member

@mwestphal mwestphal Sep 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can just store this as an std::optional<std::array<double, 3>>

double MovementVector[2] = { 1.0, 0.0 };

int RaytracingSamples = 0;
double UpVector[3] = { 0.0, 1.0, 0.0 };
Expand Down