12 #include <IJsonConvertibleIO.h>
18 #include <tinyfiledialogs/tinyfiledialogs.h>
20 #include "io/PointCloudIO.h"
21 #include "io/TriangleMeshIO.h"
30 namespace visualization {
33 std::shared_ptr<const ccHObject> geometry_ptr,
34 bool reset_bounding_box) {
39 glfwMakeContextCurrent(
window_);
44 auto ptr = std::make_shared<ccPointCloud>();
48 std::make_shared<glsl::PointCloudRenderer>();
54 auto ptr = std::make_shared<geometry::LineSet>();
58 std::make_shared<glsl::LineSetRenderer>();
64 auto ptr = std::make_shared<ccMesh>(
nullptr);
68 std::make_shared<glsl::TriangleMeshRenderer>();
74 auto ptr = std::make_shared<geometry::HalfEdgeTriangleMesh>();
78 std::make_shared<glsl::HalfEdgeMeshRenderer>();
84 auto ptr = std::make_shared<geometry::Image>();
88 std::make_shared<glsl::ImageRenderer>();
98 if (reset_bounding_box) {
102 "Add geometry and update bounding box to {}",
112 utility::LogInfo(
" X : Enter orthogonal view along X axis, press again to flip.");
113 utility::LogInfo(
" Y : Enter orthogonal view along Y axis, press again to flip.");
114 utility::LogInfo(
" Z : Enter orthogonal view along Z axis, press again to flip.");
119 utility::LogInfo(
" Shift + mouse left button : Pick a point and add in queue.");
120 utility::LogInfo(
" Shift + mouse right button : Remove last picked point from queue.");
123 utility::LogInfo(
" Mouse left button + drag : Create a selection rectangle.");
124 utility::LogInfo(
" Ctrl + mouse buttons + drag : Hold Ctrl key to draw a selection polygon.");
136 std::string new_window_title =
138 glfwSetWindowTitle(
window_, new_window_title.c_str());
150 std::make_shared<glsl::SelectionPolygonRenderer>();
167 std::make_shared<glsl::PointCloudPickerRenderer>();
178 auto renderer_ptr = std::make_shared<glsl::PointCloudPickingRenderer>();
184 glDisable(GL_MULTISAMPLE);
185 GLuint frame_buffer_name = 0;
186 glGenFramebuffers(1, &frame_buffer_name);
187 glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer_name);
189 glGenTextures(1, &fbo_texture);
190 glBindTexture(GL_TEXTURE_2D, fbo_texture);
191 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view.GetWindowWidth(),
192 view.GetWindowHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
193 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
194 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
195 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
196 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
197 if (!GLEW_ARB_framebuffer_object) {
200 "[PickPoint] Your GPU does not provide framebuffer objects. "
201 "Use a texture instead.");
202 glBindFramebuffer(GL_FRAMEBUFFER, 0);
203 glEnable(GL_MULTISAMPLE);
206 GLuint depth_render_buffer;
207 glGenRenderbuffers(1, &depth_render_buffer);
208 glBindRenderbuffer(GL_RENDERBUFFER, depth_render_buffer);
209 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT,
210 view.GetWindowWidth(), view.GetWindowHeight());
211 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
212 GL_RENDERBUFFER, depth_render_buffer);
213 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
215 GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
216 glDrawBuffers(1, DrawBuffers);
217 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
219 glBindFramebuffer(GL_FRAMEBUFFER, 0);
220 glEnable(GL_MULTISAMPLE);
223 glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer_name);
226 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
227 glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
229 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
233 glReadPixels((
int)(x + 0.5), (
int)(view.GetWindowHeight() - y + 0.5), 1, 1,
234 GL_RGBA, GL_UNSIGNED_BYTE, rgba);
238 glBindFramebuffer(GL_FRAMEBUFFER, 0);
239 glEnable(GL_MULTISAMPLE);
261 GLFWwindow *window,
int key,
int scancode,
int action,
int mods) {
264 if (action == GLFW_RELEASE) {
265 if (key == GLFW_KEY_LEFT_CONTROL || key == GLFW_KEY_RIGHT_CONTROL) {
266 if (view_control.IsLocked() &&
274 view_control.GetWindowWidth(),
275 view_control.GetWindowHeight());
288 view_control.SetEditingMode(
289 ViewControlWithEditing::EditingMode::FreeMode);
293 view_control.ToggleEditingX();
297 view_control.ToggleEditingY();
301 view_control.ToggleEditingZ();
305 view_control.ToggleLocking();
308 view_control.IsLocked() ?
"Lock" :
"Unlock");
311 if (mods & GLFW_MOD_CONTROL) {
321 if (mods & GLFW_MOD_CONTROL) {
325 const char *str = tinyfd_inputBox(
327 "Set voxel size (ignored if it is non-positive)",
331 "Illegal input, using default voxel size.");
335 double l = std::strtod(str, &end);
336 if (errno == ERANGE &&
337 (l == HUGE_VAL || l == -HUGE_VAL)) {
339 "Illegal input, using default voxel "
355 "No voxel downsample performed due to illegal "
367 glfwMakeContextCurrent(
window_);
369 if (std::shared_ptr<ccPointCloud> pcd_ptr =
371 pcd, view_control)) {
375 "Internal error: CropPointCloud returned "
380 const char *pattern[1] = {
"*.ply"};
381 std::string default_filename =
386 "ccPointCloud file", default_filename.c_str(),
387 1, pattern,
"Polygon File Format (*.ply)");
389 filename = default_filename.c_str();
393 "No filename is given. Abort saving.");
398 view_control.ToggleLocking();
403 glfwMakeContextCurrent(
window_);
405 if (std::shared_ptr<ccMesh>
mesh_ptr =
407 mesh, view_control)) {
411 "Internal error: CropTriangleMesh returned "
416 const char *pattern[1] = {
"*.ply"};
417 std::string default_filename =
422 "Mesh file", default_filename.c_str(), 1,
423 pattern,
"Polygon File Format (*.ply)");
425 filename = default_filename.c_str();
429 "No filename is given. Abort saving.");
434 view_control.ToggleLocking();
444 if (mods & GLFW_MOD_SHIFT) {
445 option.DecreaseSphereSize();
452 if (mods & GLFW_MOD_SHIFT) {
453 option.IncreaseSphereSize();
478 if (view_control.IsLocked()) {
480 x /= pixel_to_screen_coordinate_;
481 y /= pixel_to_screen_coordinate_;
483 double y_inv = view_control.GetWindowHeight() - y;
506 if (view_control.IsLocked()) {
519 if (button == GLFW_MOUSE_BUTTON_LEFT) {
521 glfwGetCursorPos(window, &x, &y);
523 x /= pixel_to_screen_coordinate_;
524 y /= pixel_to_screen_coordinate_;
526 if (action == GLFW_PRESS) {
527 double y_inv = view_control.GetWindowHeight() - y;
530 if (mods & GLFW_MOD_CONTROL) {
533 Eigen::Vector2d(x, y_inv));
535 Eigen::Vector2d(x, y_inv));
540 Eigen::Vector2d(x, y_inv));
542 Eigen::Vector2d(x, y_inv));
544 Eigen::Vector2d(x, y_inv));
546 Eigen::Vector2d(x, y_inv));
551 if (mods & GLFW_MOD_CONTROL) {
553 Eigen::Vector2d(x, y_inv);
555 Eigen::Vector2d(x, y_inv));
559 }
else if (action == GLFW_RELEASE) {
564 view_control.GetWindowWidth(),
565 view_control.GetWindowHeight());
573 }
else if (button == GLFW_MOUSE_BUTTON_RIGHT) {
574 if (action == GLFW_PRESS &&
576 (mods & GLFW_MOD_CONTROL)) {
591 if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE &&
592 (mods & GLFW_MOD_SHIFT)) {
594 glfwGetCursorPos(window, &x, &y);
596 x /= pixel_to_screen_coordinate_;
597 y /= pixel_to_screen_coordinate_;
606 static_cast<unsigned int>(index));
608 "Picked point #{:d} ({:.2}, {:.2}, {:.2}) to add in "
615 }
else if (button == GLFW_MOUSE_BUTTON_RIGHT &&
616 action == GLFW_RELEASE && (mods & GLFW_MOD_SHIFT)) {
619 "Remove picked point #{} from pick queue.",
646 std::string ply_filename =
filename;
647 if (ply_filename.empty()) {
648 ply_filename =
"CroppedGeometry.ply";
650 std::string volume_filename =
filament::Texture::InternalFormat format
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
std::shared_ptr< ccPointCloud > VoxelDownSample(double voxel_size)
Function to downsample input ccPointCloud into output ccPointCloud with a voxel.
HalfEdgeTriangleMesh inherits TriangleMesh class with the addition of HalfEdge data structure for eac...
The Image class stores image with customizable width, height, num of channels and bytes per channel.
LineSet define a sets of lines in 3D. A typical application is to display the point cloud corresponde...
void WindowResizeCallback(GLFWwindow *window, int w, int h) override
std::vector< size_t > & GetPickedPoints()
int PickPoint(double x, double y)
void SaveCroppingResult(const std::string &filename="")
void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods) override
unsigned int crop_action_count_
void KeyPressCallback(GLFWwindow *window, int key, int scancode, int action, int mods) override
std::shared_ptr< ccHObject > editing_geometry_ptr_
void BuildUtilities() override
void UpdateWindowTitle() override
std::shared_ptr< glsl::GeometryRenderer > editing_geometry_renderer_ptr_
bool InitRenderOption() override
Function to initialize RenderOption.
void MouseScrollCallback(GLFWwindow *window, double x, double y) override
bool InitViewControl() override
Function to initialize ViewControl.
std::shared_ptr< PointCloudPicker > pointcloud_picker_ptr_
SelectionMode selection_mode_
void InvalidateSelectionPolygon()
std::shared_ptr< const ccHObject > original_geometry_ptr_
std::string default_directory_
std::shared_ptr< glsl::SelectionPolygonRenderer > selection_polygon_renderer_ptr_
std::shared_ptr< SelectionPolygon > selection_polygon_ptr_
void MouseMoveCallback(GLFWwindow *window, double x, double y) override
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::shared_ptr< glsl::PointCloudPickerRenderer > pointcloud_picker_renderer_ptr_
void PrintVisualizerHelp() override
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_
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_
bool WriteIJsonConvertible(const std::string &filename, const cloudViewer::utility::IJsonConvertible &object)
bool WriteTriangleMesh(const std::string &filename, const ccMesh &mesh, bool write_ascii, bool compressed, bool write_vertex_normals, bool write_vertex_colors, bool write_triangle_uvs, bool print_progress)
bool WritePointCloud(const std::string &filename, const ccPointCloud &pointcloud, const WritePointCloudOption ¶ms)
std::string GetFileNameWithoutExtension(const std::string &filename)
int ColorCodeToPickIndex(const Eigen::Vector4i &color)
Generic file read and write utility for python interface.
Eigen::Matrix< Index, 4, 1 > Vector4i
std::string to_string(const T &n)