|
@@ -1,30 +1,88 @@
|
|
|
#include "vtk_viewer.h"
|
|
#include "vtk_viewer.h"
|
|
|
|
|
|
|
|
#include <vtkCamera.h>
|
|
#include <vtkCamera.h>
|
|
|
|
|
+#include <vtkCellArray.h>
|
|
|
#include <vtkGenericOpenGLRenderWindow.h>
|
|
#include <vtkGenericOpenGLRenderWindow.h>
|
|
|
#include <vtkGenericRenderWindowInteractor.h>
|
|
#include <vtkGenericRenderWindowInteractor.h>
|
|
|
#include <vtkInteractorStyleTrackballCamera.h>
|
|
#include <vtkInteractorStyleTrackballCamera.h>
|
|
|
#include <vtkMatrix4x4.h>
|
|
#include <vtkMatrix4x4.h>
|
|
|
#include <vtkNew.h>
|
|
#include <vtkNew.h>
|
|
|
#include <vtkOpenGLFramebufferObject.h>
|
|
#include <vtkOpenGLFramebufferObject.h>
|
|
|
|
|
+#include <vtkPointPicker.h>
|
|
|
|
|
+#include <vtkPoints.h>
|
|
|
#include <vtkPolyDataMapper.h>
|
|
#include <vtkPolyDataMapper.h>
|
|
|
|
|
+#include <vtkProperty.h>
|
|
|
#include <vtkRenderer.h>
|
|
#include <vtkRenderer.h>
|
|
|
#include <vtkSTLReader.h>
|
|
#include <vtkSTLReader.h>
|
|
|
#include <vtkTextureObject.h>
|
|
#include <vtkTextureObject.h>
|
|
|
|
|
|
|
|
#include <spdlog/spdlog.h>
|
|
#include <spdlog/spdlog.h>
|
|
|
|
|
|
|
|
|
|
+#include <vector>
|
|
|
|
|
+
|
|
|
struct vtk_viewer::impl {
|
|
struct vtk_viewer::impl {
|
|
|
|
|
|
|
|
|
|
+ struct versatile_interaction_style;
|
|
|
|
|
+
|
|
|
static constexpr auto default_focal_length = 8; // 8mm
|
|
static constexpr auto default_focal_length = 8; // 8mm
|
|
|
|
|
|
|
|
cv::Size last_size;
|
|
cv::Size last_size;
|
|
|
vtkSmartPointer<vtkGenericOpenGLRenderWindow> window;
|
|
vtkSmartPointer<vtkGenericOpenGLRenderWindow> window;
|
|
|
vtkSmartPointer<vtkCamera> camera;
|
|
vtkSmartPointer<vtkCamera> camera;
|
|
|
vtkSmartPointer<vtkRenderWindowInteractor> controller;
|
|
vtkSmartPointer<vtkRenderWindowInteractor> controller;
|
|
|
- vtkSmartPointer<vtkInteractorStyle> style;
|
|
|
|
|
|
|
+ vtkSmartPointer<versatile_interaction_style> style;
|
|
|
vtkSmartPointer<vtkRenderer> renderer;
|
|
vtkSmartPointer<vtkRenderer> renderer;
|
|
|
|
|
|
|
|
|
|
+ bool is_picking = false;
|
|
|
|
|
+ std::optional<Eigen::Vector3d> picked_point;
|
|
|
|
|
+
|
|
|
|
|
+ struct versatile_interaction_style
|
|
|
|
|
+ : public vtkInteractorStyleTrackballCamera {
|
|
|
|
|
+ vtkTypeMacro(versatile_interaction_style, vtkInteractorStyleTrackballCamera);
|
|
|
|
|
+
|
|
|
|
|
+ static versatile_interaction_style *New() {
|
|
|
|
|
+ auto ret = new versatile_interaction_style{};
|
|
|
|
|
+ ret->InitializeObjectBase();
|
|
|
|
|
+ return ret;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ impl *pimpl = nullptr;
|
|
|
|
|
+ Eigen::Vector2i mouse_down_pose;
|
|
|
|
|
+
|
|
|
|
|
+ Eigen::Vector2i get_mouse_pos() {
|
|
|
|
|
+ return {Interactor->GetEventPosition()[0],
|
|
|
|
|
+ Interactor->GetEventPosition()[1],
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void OnLeftButtonDown() override {
|
|
|
|
|
+ mouse_down_pose = get_mouse_pos();
|
|
|
|
|
+ vtkInteractorStyleTrackballCamera::OnLeftButtonDown();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ bool try_picking() {
|
|
|
|
|
+ assert(pimpl != nullptr);
|
|
|
|
|
+ if (!pimpl->is_picking) return false;
|
|
|
|
|
+ auto ret = Interactor->GetPicker()->Pick(mouse_down_pose.x(),
|
|
|
|
|
+ mouse_down_pose.y(),
|
|
|
|
|
+ 0,
|
|
|
|
|
+ pimpl->renderer);
|
|
|
|
|
+ if (ret == 0) return true; // does not pick anything
|
|
|
|
|
+ Eigen::Vector3d point;
|
|
|
|
|
+ Interactor->GetPicker()->GetPickPosition(point.data());
|
|
|
|
|
+ pimpl->picked_point = point;
|
|
|
|
|
+ SPDLOG_INFO("Picked point ({}, {}, {}).", point.x(), point.y(), point.z());
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void OnLeftButtonUp() override {
|
|
|
|
|
+ if (get_mouse_pos() == mouse_down_pose) {
|
|
|
|
|
+ try_picking();
|
|
|
|
|
+ }
|
|
|
|
|
+ vtkInteractorStyleTrackballCamera::OnLeftButtonUp();
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
static cv::Size to_cv_size(ImVec2 size) {
|
|
static cv::Size to_cv_size(ImVec2 size) {
|
|
|
return {(int) size.x, (int) size.y};
|
|
return {(int) size.x, (int) size.y};
|
|
|
}
|
|
}
|
|
@@ -40,14 +98,15 @@ struct vtk_viewer::impl {
|
|
|
// window->SetFrameBlitModeToNoBlit();
|
|
// window->SetFrameBlitModeToNoBlit();
|
|
|
|
|
|
|
|
camera = vtkSmartPointer<vtkCamera>::New();
|
|
camera = vtkSmartPointer<vtkCamera>::New();
|
|
|
- camera->SetClippingRange(100, 2000); // 10cm to 2m
|
|
|
|
|
|
|
+ camera->SetClippingRange(default_focal_length, 2000); // 8mm to 2m
|
|
|
|
|
|
|
|
renderer = vtkSmartPointer<vtkRenderer>::New();
|
|
renderer = vtkSmartPointer<vtkRenderer>::New();
|
|
|
renderer->SetUseDepthPeeling(true);
|
|
renderer->SetUseDepthPeeling(true);
|
|
|
renderer->SetActiveCamera(camera);
|
|
renderer->SetActiveCamera(camera);
|
|
|
window->AddRenderer(renderer);
|
|
window->AddRenderer(renderer);
|
|
|
|
|
|
|
|
- style = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
|
|
|
|
|
|
|
+ style = vtkSmartPointer<versatile_interaction_style>::New();
|
|
|
|
|
+ style->pimpl = this;
|
|
|
style->SetDefaultRenderer(renderer);
|
|
style->SetDefaultRenderer(renderer);
|
|
|
controller = vtkSmartPointer<vtkGenericRenderWindowInteractor>::New();
|
|
controller = vtkSmartPointer<vtkGenericRenderWindowInteractor>::New();
|
|
|
controller->SetInteractorStyle(style);
|
|
controller->SetInteractorStyle(style);
|
|
@@ -71,6 +130,7 @@ struct vtk_viewer::impl {
|
|
|
if (size != last_size) [[unlikely]] {
|
|
if (size != last_size) [[unlikely]] {
|
|
|
controller->SetSize(size.width, size.height);
|
|
controller->SetSize(size.width, size.height);
|
|
|
window->SetSize(size.width, size.height);
|
|
window->SetSize(size.width, size.height);
|
|
|
|
|
+ last_size = size;
|
|
|
}
|
|
}
|
|
|
if (interactive) {
|
|
if (interactive) {
|
|
|
process_event();
|
|
process_event();
|
|
@@ -84,7 +144,7 @@ struct vtk_viewer::impl {
|
|
|
// set event position
|
|
// set event position
|
|
|
auto &io = ImGui::GetIO();
|
|
auto &io = ImGui::GetIO();
|
|
|
io.ConfigWindowsMoveFromTitleBarOnly = true;
|
|
io.ConfigWindowsMoveFromTitleBarOnly = true;
|
|
|
- auto view_pos = ImGui::GetCursorStartPos();
|
|
|
|
|
|
|
+ auto view_pos = ImGui::GetWindowPos();
|
|
|
auto x_pos = io.MousePos.x - view_pos.x;
|
|
auto x_pos = io.MousePos.x - view_pos.x;
|
|
|
auto y_pos = io.MousePos.y - view_pos.y;
|
|
auto y_pos = io.MousePos.y - view_pos.y;
|
|
|
controller->SetEventInformationFlipY(x_pos, y_pos, io.KeyCtrl, io.KeyShift);
|
|
controller->SetEventInformationFlipY(x_pos, y_pos, io.KeyCtrl, io.KeyShift);
|
|
@@ -93,7 +153,14 @@ struct vtk_viewer::impl {
|
|
|
if (ImGui::IsWindowHovered()) {
|
|
if (ImGui::IsWindowHovered()) {
|
|
|
if (io.MouseClicked[ImGuiMouseButton_Left]) {
|
|
if (io.MouseClicked[ImGuiMouseButton_Left]) {
|
|
|
controller->InvokeEvent(vtkCommand::LeftButtonPressEvent);
|
|
controller->InvokeEvent(vtkCommand::LeftButtonPressEvent);
|
|
|
- } else if (io.MouseWheel > 0) {
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+ if (io.MouseClicked[ImGuiMouseButton_Middle]) {
|
|
|
|
|
+ controller->InvokeEvent(vtkCommand::MiddleButtonPressEvent);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (io.MouseClicked[ImGuiMouseButton_Right]) {
|
|
|
|
|
+ controller->InvokeEvent(vtkCommand::RightButtonPressEvent);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (io.MouseWheel > 0) {
|
|
|
controller->InvokeEvent(vtkCommand::MouseWheelForwardEvent);
|
|
controller->InvokeEvent(vtkCommand::MouseWheelForwardEvent);
|
|
|
} else if (io.MouseWheel < 0) {
|
|
} else if (io.MouseWheel < 0) {
|
|
|
controller->InvokeEvent(vtkCommand::MouseWheelBackwardEvent);
|
|
controller->InvokeEvent(vtkCommand::MouseWheelBackwardEvent);
|
|
@@ -102,6 +169,12 @@ struct vtk_viewer::impl {
|
|
|
if (io.MouseReleased[ImGuiMouseButton_Left]) {
|
|
if (io.MouseReleased[ImGuiMouseButton_Left]) {
|
|
|
controller->InvokeEvent(vtkCommand::LeftButtonReleaseEvent);
|
|
controller->InvokeEvent(vtkCommand::LeftButtonReleaseEvent);
|
|
|
}
|
|
}
|
|
|
|
|
+ if (io.MouseReleased[ImGuiMouseButton_Middle]) {
|
|
|
|
|
+ controller->InvokeEvent(vtkCommand::MiddleButtonReleaseEvent);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (io.MouseReleased[ImGuiMouseButton_Right]) {
|
|
|
|
|
+ controller->InvokeEvent(vtkCommand::RightButtonReleaseEvent);
|
|
|
|
|
+ }
|
|
|
controller->InvokeEvent(vtkCommand::MouseMoveEvent);
|
|
controller->InvokeEvent(vtkCommand::MouseMoveEvent);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -137,13 +210,16 @@ GLuint vtk_viewer::get_tex() const {
|
|
|
|
|
|
|
|
void vtk_viewer::add_actor(vtkActor *actor) {
|
|
void vtk_viewer::add_actor(vtkActor *actor) {
|
|
|
pimpl->renderer->AddActor(actor);
|
|
pimpl->renderer->AddActor(actor);
|
|
|
- pimpl->renderer->ResetCamera();
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void vtk_viewer::remove_actor(vtkActor *actor) {
|
|
void vtk_viewer::remove_actor(vtkActor *actor) {
|
|
|
pimpl->renderer->RemoveActor(actor);
|
|
pimpl->renderer->RemoveActor(actor);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+void vtk_viewer::clear_actor() {
|
|
|
|
|
+ pimpl->renderer->RemoveAllViewProps();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
void vtk_viewer::show(const std::string &name) {
|
|
void vtk_viewer::show(const std::string &name) {
|
|
|
pimpl->show_imgui_window(name.c_str(), ImGui::GetContentRegionAvail());
|
|
pimpl->show_imgui_window(name.c_str(), ImGui::GetContentRegionAvail());
|
|
|
}
|
|
}
|
|
@@ -157,12 +233,38 @@ void vtk_viewer::set_camera_view_angle(double angle) {
|
|
|
pimpl->camera->Modified();
|
|
pimpl->camera->Modified();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-vtkSmartPointer<vtkActor> load_stl(const std::string &path) {
|
|
|
|
|
|
|
+void vtk_viewer::start_picking() {
|
|
|
|
|
+ pimpl->is_picking = true;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void vtk_viewer::stop_picking() {
|
|
|
|
|
+ pimpl->is_picking = false;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+bool vtk_viewer::is_picking() {
|
|
|
|
|
+ return pimpl->is_picking;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+std::optional<Eigen::Vector3d> vtk_viewer::get_picked_point() {
|
|
|
|
|
+ auto ret = pimpl->picked_point;
|
|
|
|
|
+ pimpl->picked_point = {};
|
|
|
|
|
+ return ret;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void vtk_viewer::reset_camera() {
|
|
|
|
|
+ pimpl->renderer->ResetCamera();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+vtkSmartPointer<vtkPolyData> load_stl(const std::string &path) {
|
|
|
vtkNew<vtkSTLReader> reader;
|
|
vtkNew<vtkSTLReader> reader;
|
|
|
reader->SetFileName(path.c_str());
|
|
reader->SetFileName(path.c_str());
|
|
|
reader->Update();
|
|
reader->Update();
|
|
|
|
|
+ return reader->GetOutput();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+vtkSmartPointer<vtkActor> create_actor(vtkPolyData *data) {
|
|
|
vtkNew<vtkPolyDataMapper> mapper;
|
|
vtkNew<vtkPolyDataMapper> mapper;
|
|
|
- mapper->SetInputData(reader->GetOutput());
|
|
|
|
|
|
|
+ mapper->SetInputData(data);
|
|
|
vtkNew<vtkActor> actor;
|
|
vtkNew<vtkActor> actor;
|
|
|
actor->SetMapper(mapper);
|
|
actor->SetMapper(mapper);
|
|
|
vtkNew<vtkMatrix4x4> pose;
|
|
vtkNew<vtkMatrix4x4> pose;
|
|
@@ -170,14 +272,139 @@ vtkSmartPointer<vtkActor> load_stl(const std::string &path) {
|
|
|
return actor;
|
|
return actor;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void update_actor_pose(vtkActor *actor, const Eigen::Isometry3d &trans) {
|
|
|
|
|
|
|
+vtkSmartPointer<vtkActor> create_actor(const std::string &path) {
|
|
|
|
|
+ return create_actor(load_stl(path));
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void update_actor_pose(vtkActor *actor, const std::optional<Eigen::Isometry3d> &trans) {
|
|
|
|
|
+ if (!trans.has_value()) {
|
|
|
|
|
+ actor->VisibilityOff();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ actor->VisibilityOn();
|
|
|
|
|
+ auto &real_trans = trans.value();
|
|
|
auto matrix = actor->GetUserMatrix();
|
|
auto matrix = actor->GetUserMatrix();
|
|
|
assert(matrix != nullptr);
|
|
assert(matrix != nullptr);
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
for (int i = 0; i < 4; ++i) {
|
|
|
for (int j = 0; j < 4; ++j) {
|
|
for (int j = 0; j < 4; ++j) {
|
|
|
- matrix->SetElement(i, j, trans(i, j));
|
|
|
|
|
|
|
+ matrix->SetElement(i, j, real_trans(i, j));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
matrix->Modified();
|
|
matrix->Modified();
|
|
|
actor->Modified();
|
|
actor->Modified();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+struct smart_point_sets::impl {
|
|
|
|
|
+
|
|
|
|
|
+ vtkSmartPointer<vtkPoints> points;
|
|
|
|
|
+ vtkSmartPointer<vtkCellArray> vertices;
|
|
|
|
|
+ vtkSmartPointer<vtkPolyData> poly;
|
|
|
|
|
+ vtkSmartPointer<vtkActor> actor;
|
|
|
|
|
+
|
|
|
|
|
+ std::vector<Eigen::Vector3d> points_store;
|
|
|
|
|
+
|
|
|
|
|
+ impl() {
|
|
|
|
|
+ actor = vtkSmartPointer<vtkActor>::New();
|
|
|
|
|
+ actor->GetProperty()->SetRenderPointsAsSpheres(true);
|
|
|
|
|
+ actor->GetProperty()->SetPointSize(10);
|
|
|
|
|
+ reconstruct();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void add_point_to_poly(const Eigen::Vector3d &point) {
|
|
|
|
|
+ vtkIdType pid[1];
|
|
|
|
|
+ pid[0] = points->InsertNextPoint(point.data());
|
|
|
|
|
+ points->Modified();
|
|
|
|
|
+ vertices->InsertNextCell(1, pid);
|
|
|
|
|
+ vertices->Modified();
|
|
|
|
|
+ poly->Modified();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ auto add_point(const Eigen::Vector3d &point) {
|
|
|
|
|
+ points_store.emplace_back(point);
|
|
|
|
|
+ add_point_to_poly(point);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void reconstruct() {
|
|
|
|
|
+ points = vtkSmartPointer<vtkPoints>::New();
|
|
|
|
|
+ vertices = vtkSmartPointer<vtkCellArray>::New();
|
|
|
|
|
+ poly = vtkSmartPointer<vtkPolyData>::New();
|
|
|
|
|
+ poly->SetPoints(points);
|
|
|
|
|
+ poly->SetVerts(vertices);
|
|
|
|
|
+ vtkNew<vtkPolyDataMapper> mapper;
|
|
|
|
|
+ mapper->SetInputData(poly);
|
|
|
|
|
+ actor->SetMapper(mapper);
|
|
|
|
|
+ actor->Modified();
|
|
|
|
|
+
|
|
|
|
|
+ for (auto &p: points_store) {
|
|
|
|
|
+ add_point_to_poly(p);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void for_each(const for_each_func_type &func) {
|
|
|
|
|
+ for (auto iter = points_store.begin();
|
|
|
|
|
+ iter != points_store.end();
|
|
|
|
|
+ ++iter) {
|
|
|
|
|
+ func(*(void **) &iter, *iter);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void remove_point(void *token) {
|
|
|
|
|
+ using iter_type = decltype(points_store)::iterator;
|
|
|
|
|
+ points_store.erase(*(iter_type *) (&token));
|
|
|
|
|
+ reconstruct();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Eigen::Vector3d pop_front() {
|
|
|
|
|
+ assert(!points_store.empty());
|
|
|
|
|
+ auto ret = points_store.front();
|
|
|
|
|
+ points_store.erase(points_store.begin());
|
|
|
|
|
+ reconstruct();
|
|
|
|
|
+ return ret;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+smart_point_sets::smart_point_sets()
|
|
|
|
|
+ : pimpl(std::make_unique<impl>()) {}
|
|
|
|
|
+
|
|
|
|
|
+smart_point_sets::~smart_point_sets() = default;
|
|
|
|
|
+
|
|
|
|
|
+void smart_point_sets::add_point(const Eigen::Vector3d &point) {
|
|
|
|
|
+ pimpl->add_point(point);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+vtkActor *smart_point_sets::get_actor() {
|
|
|
|
|
+ return pimpl->actor;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void smart_point_sets::for_each(const for_each_func_type &func) {
|
|
|
|
|
+ pimpl->for_each(func);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void smart_point_sets::remove_point(void *token) {
|
|
|
|
|
+ pimpl->remove_point(token);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+Eigen::Vector3d smart_point_sets::pop_front() {
|
|
|
|
|
+ return pimpl->pop_front();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+bool smart_point_sets::empty() const {
|
|
|
|
|
+ return pimpl->points_store.empty();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+size_t smart_point_sets::size() const {
|
|
|
|
|
+ return pimpl->points_store.size();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+std::vector<Eigen::Vector3d> smart_point_sets::to_vector() const {
|
|
|
|
|
+ return pimpl->points_store;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+Eigen::Vector3d smart_point_sets::operator[](size_t index) const {
|
|
|
|
|
+ return pimpl->points_store[index];
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void smart_point_sets::clear() const {
|
|
|
|
|
+ pimpl->points_store.clear();
|
|
|
|
|
+ pimpl->reconstruct();
|
|
|
}
|
|
}
|