vtk_viewer.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. #include "vtk_viewer.h"
  2. #include "core/utility.hpp"
  3. #include <vtkCamera.h>
  4. #include <vtkCellArray.h>
  5. #include <vtkGenericOpenGLRenderWindow.h>
  6. #include <vtkGenericRenderWindowInteractor.h>
  7. #include <vtkInteractorStyleTrackballCamera.h>
  8. #include <vtkMatrix4x4.h>
  9. #include <vtkNew.h>
  10. #include <vtkOBJReader.h>
  11. #include <vtkOpenGLFramebufferObject.h>
  12. #include <vtkPointPicker.h>
  13. #include <vtkPoints.h>
  14. #include <vtkPolyDataMapper.h>
  15. #include <vtkProperty.h>
  16. #include <vtkRenderer.h>
  17. #include <vtkSTLReader.h>
  18. #include <vtkTextureObject.h>
  19. #include <spdlog/spdlog.h>
  20. #include <filesystem>
  21. #include <vector>
  22. namespace vtk_viewer_impl {
  23. Eigen::Isometry3d to_eigen_transform(vtkMatrix4x4 *mat) {
  24. Eigen::Isometry3d ret;
  25. for (int i = 0; i < 4; ++i)
  26. for (int j = 0; j < 4; ++j)
  27. ret.matrix()(i, j) = mat->GetElement(i, j);
  28. return ret;
  29. }
  30. }
  31. using namespace vtk_viewer_impl;
  32. struct vtk_viewer::impl {
  33. struct versatile_interaction_style;
  34. static constexpr auto default_focal_length = 8; // 8mm
  35. cv::Size last_size;
  36. vtkSmartPointer<vtkGenericOpenGLRenderWindow> window;
  37. vtkSmartPointer<vtkCamera> camera;
  38. vtkSmartPointer<vtkRenderWindowInteractor> controller;
  39. vtkSmartPointer<versatile_interaction_style> style;
  40. vtkSmartPointer<vtkRenderer> renderer;
  41. bool is_picking = false;
  42. std::optional<Eigen::Vector3d> picked_point;
  43. struct versatile_interaction_style
  44. : public vtkInteractorStyleTrackballCamera {
  45. vtkTypeMacro(versatile_interaction_style, vtkInteractorStyleTrackballCamera);
  46. static versatile_interaction_style *New() {
  47. auto ret = new versatile_interaction_style{};
  48. ret->InitializeObjectBase();
  49. return ret;
  50. }
  51. impl *pimpl = nullptr;
  52. Eigen::Vector2i mouse_down_pose;
  53. Eigen::Vector2i get_mouse_pos() {
  54. return {Interactor->GetEventPosition()[0],
  55. Interactor->GetEventPosition()[1],
  56. };
  57. }
  58. void OnLeftButtonDown() override {
  59. mouse_down_pose = get_mouse_pos();
  60. vtkInteractorStyleTrackballCamera::OnLeftButtonDown();
  61. }
  62. bool try_picking() {
  63. assert(pimpl != nullptr);
  64. if (!pimpl->is_picking) return false;
  65. auto ret = Interactor->GetPicker()->Pick(mouse_down_pose.x(),
  66. mouse_down_pose.y(),
  67. 0,
  68. pimpl->renderer);
  69. if (ret == 0) return true; // does not pick anything
  70. Eigen::Vector3d point;
  71. Interactor->GetPicker()->GetPickPosition(point.data());
  72. pimpl->picked_point = point;
  73. SPDLOG_INFO("Picked point ({}, {}, {}).", point.x(), point.y(), point.z());
  74. return true;
  75. }
  76. void OnLeftButtonUp() override {
  77. if (get_mouse_pos() == mouse_down_pose) {
  78. try_picking();
  79. }
  80. vtkInteractorStyleTrackballCamera::OnLeftButtonUp();
  81. }
  82. };
  83. static cv::Size to_cv_size(ImVec2 size) {
  84. return {(int) size.x, (int) size.y};
  85. }
  86. impl() {
  87. window = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
  88. window->InitializeFromCurrentContext();
  89. window->SetOffScreenRendering(true);
  90. window->SetAlphaBitPlanes(true);
  91. // window->FramebufferFlipYOn();
  92. window->SetIsCurrent(true);
  93. // window->SwapBuffersOn();
  94. // window->SetFrameBlitModeToNoBlit();
  95. camera = vtkSmartPointer<vtkCamera>::New();
  96. camera->SetClippingRange(default_focal_length, 2000); // 8mm to 2m
  97. renderer = vtkSmartPointer<vtkRenderer>::New();
  98. renderer->SetUseDepthPeeling(true);
  99. renderer->SetActiveCamera(camera);
  100. window->AddRenderer(renderer);
  101. style = vtkSmartPointer<versatile_interaction_style>::New();
  102. style->pimpl = this;
  103. style->SetDefaultRenderer(renderer);
  104. controller = vtkSmartPointer<vtkGenericRenderWindowInteractor>::New();
  105. controller->SetInteractorStyle(style);
  106. controller->EnableRenderOff();
  107. window->SetInteractor(controller);
  108. }
  109. void set_camera_pose(const Eigen::Isometry3d &trans) {
  110. auto trans_part = trans.translation();
  111. auto rot_part = trans.rotation();
  112. auto focal_point = trans_part + rot_part.col(2) * default_focal_length;
  113. auto view_up = -rot_part.col(1);
  114. camera->SetPosition(trans_part.x(), trans_part.y(), trans_part.z());
  115. camera->SetFocalPoint(focal_point.x(), focal_point.y(), focal_point.z());
  116. camera->SetViewUp(view_up.x(), view_up.y(), view_up.z());
  117. camera->Modified();
  118. }
  119. void render(cv::Size size, bool interactive) {
  120. assert(size.area() > 0);
  121. if (size != last_size) [[unlikely]] {
  122. controller->SetSize(size.width, size.height);
  123. window->SetSize(size.width, size.height);
  124. last_size = size;
  125. }
  126. if (interactive) {
  127. process_event();
  128. }
  129. window->Render();
  130. }
  131. void process_event() {
  132. if (!ImGui::IsWindowFocused() || !ImGui::IsWindowHovered()) return;
  133. // set event position
  134. auto &io = ImGui::GetIO();
  135. io.ConfigWindowsMoveFromTitleBarOnly = true;
  136. auto view_pos = ImGui::GetWindowPos();
  137. auto x_pos = io.MousePos.x - view_pos.x;
  138. auto y_pos = io.MousePos.y - view_pos.y;
  139. // flip X axis
  140. x_pos = controller->GetSize()[0] - x_pos;
  141. controller->SetEventInformation(x_pos, y_pos, io.KeyCtrl, io.KeyShift);
  142. // dispatch event
  143. if (ImGui::IsWindowHovered()) {
  144. if (io.MouseClicked[ImGuiMouseButton_Left]) {
  145. controller->InvokeEvent(vtkCommand::LeftButtonPressEvent);
  146. }
  147. if (io.MouseClicked[ImGuiMouseButton_Middle]) {
  148. controller->InvokeEvent(vtkCommand::MiddleButtonPressEvent);
  149. }
  150. if (io.MouseClicked[ImGuiMouseButton_Right]) {
  151. controller->InvokeEvent(vtkCommand::RightButtonPressEvent);
  152. }
  153. if (io.MouseWheel > 0) {
  154. controller->InvokeEvent(vtkCommand::MouseWheelForwardEvent);
  155. } else if (io.MouseWheel < 0) {
  156. controller->InvokeEvent(vtkCommand::MouseWheelBackwardEvent);
  157. }
  158. }
  159. if (io.MouseReleased[ImGuiMouseButton_Left]) {
  160. controller->InvokeEvent(vtkCommand::LeftButtonReleaseEvent);
  161. }
  162. if (io.MouseReleased[ImGuiMouseButton_Middle]) {
  163. controller->InvokeEvent(vtkCommand::MiddleButtonReleaseEvent);
  164. }
  165. if (io.MouseReleased[ImGuiMouseButton_Right]) {
  166. controller->InvokeEvent(vtkCommand::RightButtonReleaseEvent);
  167. }
  168. controller->InvokeEvent(vtkCommand::MouseMoveEvent);
  169. }
  170. GLuint get_tex() const {
  171. return window->GetDisplayFramebuffer()
  172. ->GetColorAttachmentAsTextureObject(0)->GetHandle();
  173. }
  174. void show_imgui_window(const char *name, ImVec2 req_size) {
  175. ImGui::BeginChild(name, req_size, 0, no_scroll_flag);
  176. auto render_size = ImGui::GetContentRegionAvail();
  177. auto render_size_cv = to_cv_size(render_size);
  178. if (render_size_cv.area() <= 0)return;
  179. render(render_size_cv, true);
  180. ImGui::Image(reinterpret_cast<void *>(get_tex()), render_size, {1, 0}, {0, 1});
  181. ImGui::EndChild();
  182. }
  183. };
  184. vtk_viewer::vtk_viewer()
  185. : pimpl(std::make_unique<impl>()) {}
  186. vtk_viewer::~vtk_viewer() = default;
  187. void vtk_viewer::render(cv::Size size) {
  188. return pimpl->render(size, false);
  189. }
  190. GLuint vtk_viewer::get_tex() const {
  191. return pimpl->get_tex();
  192. }
  193. void vtk_viewer::add_actor(vtkActor *actor) {
  194. pimpl->renderer->AddActor(actor);
  195. }
  196. void vtk_viewer::remove_actor(vtkActor *actor) {
  197. pimpl->renderer->RemoveActor(actor);
  198. }
  199. void vtk_viewer::clear_actor() {
  200. pimpl->renderer->RemoveAllViewProps();
  201. }
  202. void vtk_viewer::show(const std::string &name) {
  203. pimpl->show_imgui_window(name.c_str(), ImGui::GetContentRegionAvail());
  204. }
  205. Eigen::Isometry3d vtk_viewer::get_camera_pose() {
  206. auto ret = to_eigen_transform( // world in camera, I think
  207. pimpl->camera->GetModelViewTransformMatrix());
  208. ret = ret.inverse() * Eigen::AngleAxisd{std::numbers::pi, Eigen::Vector3d::UnitX()};
  209. return ret;
  210. }
  211. void vtk_viewer::set_camera_pose(const Eigen::Isometry3d &trans) {
  212. pimpl->set_camera_pose(trans);
  213. }
  214. void vtk_viewer::set_camera_view_angle(double angle) {
  215. pimpl->camera->SetViewAngle(angle);
  216. pimpl->camera->Modified();
  217. }
  218. void vtk_viewer::start_picking() {
  219. pimpl->is_picking = true;
  220. }
  221. void vtk_viewer::stop_picking() {
  222. pimpl->is_picking = false;
  223. }
  224. bool vtk_viewer::is_picking() {
  225. return pimpl->is_picking;
  226. }
  227. std::optional<Eigen::Vector3d> vtk_viewer::get_picked_point() {
  228. auto ret = pimpl->picked_point;
  229. pimpl->picked_point = {};
  230. return ret;
  231. }
  232. void vtk_viewer::reset_camera() {
  233. pimpl->renderer->ResetCamera();
  234. }
  235. namespace vtk_viewer_helper {
  236. vtkSmartPointer<vtkPolyData> load_stl(const std::string &path) {
  237. vtkNew<vtkSTLReader> reader;
  238. reader->SetFileName(path.c_str());
  239. reader->Update();
  240. return reader->GetOutput();
  241. }
  242. vtkSmartPointer<vtkPolyData> load_obj(const std::string &path) {
  243. vtkNew<vtkOBJReader> reader;
  244. reader->SetFileName(path.c_str());
  245. reader->Update();
  246. return reader->GetOutput();
  247. }
  248. vtkSmartPointer<vtkPolyData> load_any(const std::string &path) {
  249. auto path_fs = std::filesystem::path{path};
  250. auto ext = path_fs.extension();
  251. if (ext == ".stl") {
  252. return load_stl(path);
  253. } else if (ext == ".obj") {
  254. return load_obj(path);
  255. }
  256. RET_ERROR_P;
  257. }
  258. vtkSmartPointer<vtkActor> create_actor(vtkPolyData *data) {
  259. vtkNew<vtkPolyDataMapper> mapper;
  260. mapper->SetInputData(data);
  261. vtkNew<vtkActor> actor;
  262. actor->SetMapper(mapper);
  263. vtkNew<vtkMatrix4x4> pose;
  264. actor->SetUserMatrix(pose);
  265. return actor;
  266. }
  267. vtkSmartPointer<vtkActor> create_actor(const std::string &path) {
  268. return create_actor(load_stl(path));
  269. }
  270. void update_actor_pose(vtkActor *actor, const std::optional<Eigen::Isometry3d> &trans) {
  271. if (!trans.has_value()) {
  272. actor->VisibilityOff();
  273. return;
  274. }
  275. actor->VisibilityOn();
  276. auto &real_trans = trans.value();
  277. auto matrix = actor->GetUserMatrix();
  278. if (matrix == nullptr) {
  279. actor->SetUserMatrix(vtkMatrix4x4::New());
  280. matrix = actor->GetUserMatrix();
  281. }
  282. for (int i = 0; i < 4; ++i) {
  283. for (int j = 0; j < 4; ++j) {
  284. matrix->SetElement(i, j, real_trans(i, j));
  285. }
  286. }
  287. matrix->Modified();
  288. actor->Modified();
  289. }
  290. }
  291. struct smart_point_sets::impl {
  292. vtkSmartPointer<vtkPoints> points;
  293. vtkSmartPointer<vtkCellArray> vertices;
  294. vtkSmartPointer<vtkPolyData> poly;
  295. vtkSmartPointer<vtkActor> actor;
  296. std::vector<Eigen::Vector3d> points_store;
  297. impl() {
  298. actor = vtkSmartPointer<vtkActor>::New();
  299. actor->GetProperty()->SetRenderPointsAsSpheres(true);
  300. actor->GetProperty()->SetPointSize(10);
  301. reconstruct();
  302. }
  303. void add_point_to_poly(const Eigen::Vector3d &point) {
  304. vtkIdType pid[1];
  305. pid[0] = points->InsertNextPoint(point.data());
  306. points->Modified();
  307. vertices->InsertNextCell(1, pid);
  308. vertices->Modified();
  309. poly->Modified();
  310. }
  311. auto add_point(const Eigen::Vector3d &point) {
  312. points_store.emplace_back(point);
  313. add_point_to_poly(point);
  314. }
  315. void reconstruct() {
  316. points = vtkSmartPointer<vtkPoints>::New();
  317. vertices = vtkSmartPointer<vtkCellArray>::New();
  318. poly = vtkSmartPointer<vtkPolyData>::New();
  319. poly->SetPoints(points);
  320. poly->SetVerts(vertices);
  321. vtkNew<vtkPolyDataMapper> mapper;
  322. mapper->SetInputData(poly);
  323. actor->SetMapper(mapper);
  324. actor->Modified();
  325. for (auto &p: points_store) {
  326. add_point_to_poly(p);
  327. }
  328. }
  329. void for_each(const for_each_func_type &func) {
  330. for (auto iter = points_store.begin();
  331. iter != points_store.end();
  332. ++iter) {
  333. func(*(void **) &iter, *iter);
  334. }
  335. }
  336. void remove_point(void *token) {
  337. using iter_type = decltype(points_store)::iterator;
  338. points_store.erase(*(iter_type *) (&token));
  339. reconstruct();
  340. }
  341. Eigen::Vector3d pop_front() {
  342. assert(!points_store.empty());
  343. auto ret = points_store.front();
  344. points_store.erase(points_store.begin());
  345. reconstruct();
  346. return ret;
  347. }
  348. };
  349. smart_point_sets::smart_point_sets()
  350. : pimpl(std::make_unique<impl>()) {}
  351. smart_point_sets::~smart_point_sets() = default;
  352. void smart_point_sets::add_point(const Eigen::Vector3d &point) {
  353. pimpl->add_point(point);
  354. }
  355. vtkActor *smart_point_sets::get_actor() {
  356. return pimpl->actor;
  357. }
  358. void smart_point_sets::for_each(const for_each_func_type &func) {
  359. pimpl->for_each(func);
  360. }
  361. void smart_point_sets::remove_point(void *token) {
  362. pimpl->remove_point(token);
  363. }
  364. Eigen::Vector3d smart_point_sets::pop_front() {
  365. return pimpl->pop_front();
  366. }
  367. bool smart_point_sets::empty() const {
  368. return pimpl->points_store.empty();
  369. }
  370. size_t smart_point_sets::size() const {
  371. return pimpl->points_store.size();
  372. }
  373. std::vector<Eigen::Vector3d> smart_point_sets::to_vector() const {
  374. return pimpl->points_store;
  375. }
  376. Eigen::Vector3d smart_point_sets::operator[](size_t index) const {
  377. return pimpl->points_store[index];
  378. }
  379. void smart_point_sets::clear() const {
  380. pimpl->points_store.clear();
  381. pimpl->reconstruct();
  382. }