12 #include <IJsonConvertibleIO.h>
20 #include <tinyfiledialogs/tinyfiledialogs.h>
22 #include "io/PointCloudIO.h"
23 #include "io/TriangleMeshIO.h"
32 namespace visualization {
35 static const double POINT_SIZE = 9.0;
36 static const double MIN_POINT_SIZE = 3.0;
37 static const Eigen::Vector3d CHOOSE_POINTS_COLOR(1, 0, 1);
38 static const Eigen::Vector3d SELECTED_POINTS_COLOR(0, 1, 0);
39 static const int START_RECT_DIST = 3;
42 GLuint frame_buffer_name = 0;
43 glGenFramebuffers(1, &frame_buffer_name);
44 glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer_name);
46 glGenTextures(1, &fbo_texture);
47 glBindTexture(GL_TEXTURE_2D, fbo_texture);
48 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
width,
height, 0, GL_RGBA,
50 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
51 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
52 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
53 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
54 if (!GLEW_ARB_framebuffer_object) {
57 "[BindFramebuffwer] Your GPU does not provide framebuffer "
59 "Use a texture instead.");
62 GLuint depth_render_buffer;
63 glGenRenderbuffers(1, &depth_render_buffer);
64 glBindRenderbuffer(GL_RENDERBUFFER, depth_render_buffer);
65 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT,
width,
height);
66 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
67 GL_RENDERBUFFER, depth_render_buffer);
68 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
70 GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
71 glDrawBuffers(1, DrawBuffers);
72 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
83 std::shared_ptr<const ccHObject> geometry_in_ptr,
84 bool reset_bounding_box) {
87 "VisualizerWithVertexSelection only supports one geometry");
90 glfwMakeContextCurrent(
window_);
97 std::make_shared<glsl::PointCloudRenderer>();
104 std::make_shared<glsl::TriangleMeshRenderer>();
108 std::make_shared<glsl::HalfEdgeMeshRenderer>();
112 std::make_shared<glsl::TetraMeshRenderer>();
142 std::make_shared<glsl::PointCloudRenderer>();
153 if (reset_bounding_box) {
157 "Add geometry and update bounding box to {}",
163 std::shared_ptr<const ccHObject> geometry_ptr ) {
166 "VisualizerWithVertexSelection::UpdateGeometry() does not "
168 "passing a new geometry. However, you may update the geometry "
170 "passed to AddGeometry() and call UpdateGeometry().");
187 if (cloud->hasNormals()) {
197 auto lines = std::static_pointer_cast<const geometry::LineSet>(
199 if (lines->points_.size() !=
207 auto mesh = std::static_pointer_cast<const ccMesh>(
geometry_ptr_);
221 auto mesh = std::static_pointer_cast<const geometry::ecvMeshBase>(
223 if (mesh->vertices_.size() !=
254 utility::LogInfo(
" X : Enter orthogonal view along X axis, press again to flip.");
255 utility::LogInfo(
" Y : Enter orthogonal view along Y axis, press again to flip.");
256 utility::LogInfo(
" Z : Enter orthogonal view along Z axis, press again to flip.");
259 utility::LogInfo(
" Shift + mouse left button : Pick a point and add to selection. If it is");
261 utility::LogInfo(
" Shift + mouse left drag : Defines a rectangle, which will add all the ");
264 utility::LogInfo(
" Delete / Backspace : Removes all points in the rectangle from the");
273 auto title =
window_name_ +
" - " + view_control.GetStatusString();
274 glfwSetWindowTitle(
window_, title.c_str());
286 std::make_shared<glsl::SelectionPolygonRenderer>();
303 std::make_shared<glsl::PointCloudPickerRenderer>();
317 if (!BindFramebuffer(view.GetWindowWidth(), view.GetWindowHeight())) {
318 glBindFramebuffer(GL_FRAMEBUFFER, 0);
324 glDisable(GL_MULTISAMPLE);
326 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
327 glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
329 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
336 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
337 glEnable(GL_MULTISAMPLE);
342 int lowerLeftX = int(winX + 0.5);
343 int lowerLeftY = int(view.GetWindowHeight() - winY -
height + 0.5);
346 glReadPixels(lowerLeftX, lowerLeftY,
width,
height, GL_DEPTH_COMPONENT,
349 glBindFramebuffer(GL_FRAMEBUFFER, 0);
359 auto renderer_ptr = std::make_shared<glsl::PointCloudPickingRenderer>();
365 if (!BindFramebuffer(view.GetWindowWidth(), view.GetWindowHeight())) {
366 glBindFramebuffer(GL_FRAMEBUFFER, 0);
371 glDisable(GL_MULTISAMPLE);
373 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
374 glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
376 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
380 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
386 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
396 int lowerLeftX = int(winX + 0.5);
397 int lowerLeftY = int(view.GetWindowHeight() - winY -
height + 0.5);
400 glReadPixels(lowerLeftX, lowerLeftY,
width,
height, GL_RGBA,
401 GL_UNSIGNED_BYTE, rgba.data());
403 glBindFramebuffer(GL_FRAMEBUFFER, 0);
404 glEnable(GL_MULTISAMPLE);
406 std::unordered_set<int> indexSet;
408 const uint8_t *rgbaPtr = rgba.data() + 4 * i;
410 rgbaPtr[0], rgbaPtr[1], rgbaPtr[2], rgbaPtr[3]));
412 indexSet.insert(index);
416 std::vector<int> indices;
417 indices.reserve(indexSet.size());
418 for (
int idx : indexSet) {
419 indices.push_back(idx);
425 std::vector<VisualizerWithVertexSelection::PickedPoint>
427 std::vector<PickedPoint>
points;
430 points.push_back({kv.first, kv.second});
449 std::function<
void()> f) {
454 std::function<
void()> f) {
459 std::function<
void()> f) {
471 GLFWwindow *window,
int key,
int scancode,
int action,
int mods) {
473 if (key == GLFW_KEY_LEFT_SHIFT || key == GLFW_KEY_RIGHT_SHIFT) {
474 if (action == GLFW_PRESS) {
479 }
else if (action == GLFW_RELEASE) {
491 }
else if ((key == GLFW_KEY_DELETE || key == GLFW_KEY_BACKSPACE) &&
492 action == GLFW_RELEASE) {
500 view_control.ToggleEditingX();
504 view_control.ToggleEditingY();
508 view_control.ToggleEditingZ();
512 if (mods & GLFW_MOD_CONTROL) {
515 SELECTED_POINTS_COLOR);
523 case GLFW_KEY_MINUS: {
524 if (action == GLFW_PRESS) {
533 case GLFW_KEY_EQUAL: {
534 if (action == GLFW_PRESS) {
557 x /= pixel_to_screen_coordinate_;
558 y /= pixel_to_screen_coordinate_;
560 double y_inv = view_control.GetWindowHeight() - y;
567 Eigen::Vector2d pt(x, y_inv);
599 glfwGetCursorPos(window, &x, &y);
601 x /= pixel_to_screen_coordinate_;
602 y /= pixel_to_screen_coordinate_;
605 if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) {
606 if (mods & GLFW_MOD_SHIFT) {
612 }
else if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE) {
615 if (indices.empty()) {
618 int index = indices[0];
628 auto winHeight = view_control.GetWindowHeight();
644 if (indices.empty()) {
657 }
else if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS) {
666 auto depth =
GetDepth(
static_cast<int>(x),
static_cast<int>(y));
673 }
else if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_RELEASE) {
710 const std::vector<int> indices) {
711 const std::vector<Eigen::Vector3d> *eigenPoints =
nullptr;
712 const std::vector<CCVector3> *
points =
nullptr;
726 for (
auto &index : indices) {
728 const auto &
point = (*eigenPoints)[index];
730 "Adding point #{:d} ({:.2f}, {:.2f}, {:.2f}) to selection.",
735 const auto &
point = (*points)[index];
737 "Adding point #{:d} ({:.2f}, {:.2f}, {:.2f}) to selection.",
753 const std::vector<int> indices) {
754 for (
auto &index : indices) {
774 auto index = kv.first;
775 auto new_coord = kv.second + delta;
789 const std::vector<Eigen::Vector3d> *
791 std::shared_ptr<const ccHObject> geometry) {
792 const std::vector<Eigen::Vector3d> *
points =
nullptr;
793 switch (geometry->getClassID()) {
796 std::static_pointer_cast<const geometry::LineSet>(geometry);
802 auto mesh = std::static_pointer_cast<const geometry::ecvMeshBase>(
804 points = &mesh->vertices_;
821 std::shared_ptr<const ccHObject> geometry) {
822 const std::vector<CCVector3> *
points =
nullptr;
823 switch (geometry->getClassID()) {
825 auto cloud = std::static_pointer_cast<const ccPointCloud>(geometry);
826 points = &cloud->getPoints();
831 auto mesh = std::static_pointer_cast<const ccMesh>(geometry);
832 points = &mesh->getVertices();
855 view.GetMVPMatrix(), view.GetWindowWidth(), view.GetWindowHeight());
857 Eigen::Vector3d(winX, view.GetWindowHeight() - winY,
drag_depth_),
858 view.GetMVPMatrix(), view.GetWindowWidth(), view.GetWindowHeight());
866 opt->SetPointSize(
size);
868 opt->SetPointSize(
size);
static Vector3Tpl fromArray(const int a[3])
Constructor from an int array.
static ccPointCloud * ToPointCloud(ccHObject *obj, bool *isLockedVertices=nullptr)
Converts current object to 'equivalent' ccPointCloud.
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
unsigned size() const override
double point_size_
Point size for PointCloud.
void SetPointSize(double size)
void BuildUtilities() override
std::shared_ptr< glsl::GeometryRenderer > ui_selected_points_renderer_ptr_
std::shared_ptr< glsl::GeometryRenderer > ui_points_renderer_ptr_
void RegisterSelectionChangedCallback(std::function< void()> f)
std::shared_ptr< ccPointCloud > ui_points_geometry_ptr_
std::shared_ptr< glsl::SelectionPolygonRenderer > selection_polygon_renderer_ptr_
Eigen::Vector3d CalcDragDelta(double winX, double winY)
std::shared_ptr< PointCloudPicker > pointcloud_picker_ptr_
const std::vector< Eigen::Vector3d > * GetGeometryEigenPoints(std::shared_ptr< const ccHObject > geometry)
bool AddGeometry(std::shared_ptr< const ccHObject > geometry_ptr, bool reset_bounding_box=true) override
Function to add geometry to the scene and create corresponding shaders.
std::function< void()> on_selection_changed_
void MouseMoveCallback(GLFWwindow *window, double x, double y) override
void KeyPressCallback(GLFWwindow *window, int key, int scancode, int action, int mods) override
RenderOption pick_point_opts_
void InvalidateSelectionPolygon()
void RegisterSelectionMovingCallback(std::function< void()> f)
std::vector< PickedPoint > GetPickedPoints() const
std::shared_ptr< const ccHObject > geometry_ptr_
std::shared_ptr< ccPointCloud > ui_selected_points_geometry_ptr_
std::unordered_map< int, Eigen::Vector3d > selected_points_before_drag_
std::shared_ptr< SelectionPolygon > selection_polygon_ptr_
void SetPointSize(double size)
std::shared_ptr< glsl::GeometryRenderer > geometry_renderer_ptr_
void RemovePickedPoints(const std::vector< int > indices)
std::unordered_map< int, Eigen::Vector3d > selected_points_
void AddPickedPoints(const std::vector< int > indices)
const std::vector< CCVector3 > * GetGeometryPoints(std::shared_ptr< const ccHObject > geometry)
void UpdateWindowTitle() override
bool UpdateGeometry(std::shared_ptr< const ccHObject > geometry_ptr=nullptr) override
Function to update geometry.
std::vector< int > PickPoints(double x, double y, double w, double h)
void RegisterSelectionMovedCallback(std::function< void()> f)
std::vector< int > points_in_rect_
void MouseScrollCallback(GLFWwindow *window, double x, double y) override
void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods) override
std::shared_ptr< glsl::PointCloudPickerRenderer > pointcloud_picker_renderer_ptr_
void PrintVisualizerHelp() override
void WindowResizeCallback(GLFWwindow *window, int w, int h) override
SelectionMode selection_mode_
bool InitViewControl() override
Function to initialize ViewControl.
bool InitRenderOption() override
Function to initialize RenderOption.
Eigen::Vector2d mouse_down_pos_
std::function< void()> on_selection_moved_
void DragSelectedPoints(const Eigen::Vector3d &delta, DragType type)
std::function< void()> on_selection_moving_
float GetDepth(int winX, int winY)
virtual bool UpdateGeometry(std::shared_ptr< const ccHObject > geometry_ptr=nullptr)
Function to update geometry.
virtual void KeyPressCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
std::vector< std::shared_ptr< glsl::GeometryRenderer > > utility_renderer_ptrs_
RenderOption & GetRenderOption()
Function to retrieve the associated RenderOption.
virtual void MouseScrollCallback(GLFWwindow *window, double x, double y)
std::unordered_set< std::shared_ptr< const ccHObject > > geometry_ptrs_
std::unordered_map< std::shared_ptr< glsl::GeometryRenderer >, RenderOption > utility_renderer_opts_
virtual void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods)
std::unique_ptr< RenderOption > render_option_ptr_
virtual void MouseMoveCallback(GLFWwindow *window, double x, double y)
void ResetViewPoint(bool reset_bounding_box=false)
Function to reset view point.
virtual void BuildUtilities()
std::unordered_set< std::shared_ptr< glsl::GeometryRenderer > > geometry_renderer_ptrs_
std::unique_ptr< ViewControl > view_control_ptr_
ViewControl & GetViewControl()
Function to retrieve the associated ViewControl.
virtual void WindowResizeCallback(GLFWwindow *window, int w, int h)
virtual void PrintVisualizerHelp()
std::vector< std::shared_ptr< const ccHObject > > utility_ptrs_
__host__ __device__ int2 abs(int2 v)
MiniVec< float, N > ceil(const MiniVec< float, N > &a)
Eigen::Vector3d Unproject(const Eigen::Vector3d &screen_point, const GLMatrix4f &mvp_matrix, const int width, const int height)
int ColorCodeToPickIndex(const Eigen::Vector4i &color)
Generic file read and write utility for python interface.
Eigen::Matrix< Index, 4, 1 > Vector4i