From 13e377189d4d89ee4f4598e7eff5ccf0d6eb928a Mon Sep 17 00:00:00 2001 From: Nicholas Sharp Date: Wed, 19 Mar 2025 22:59:28 -0700 Subject: [PATCH 1/6] initial work on selection bindings --- src/cpp/core.cpp | 22 ++++++++++++++++++++++ src/polyscope/core.py | 21 ++++++++++++++++++--- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/cpp/core.cpp b/src/cpp/core.cpp index 792d709..8b50fed 100644 --- a/src/cpp/core.cpp +++ b/src/cpp/core.cpp @@ -207,6 +207,21 @@ PYBIND11_MODULE(polyscope_bindings, m) { m.def("clear_user_callback", []() {ps::state::userCallback = nullptr;}); // === Pick + + py::class_(m, "PickResult") + .def(py::init<>()) + .def_readonly("is_hit", &ps::PickResult::isHit) + // .def_readonly("structure", &ps::PickResult::structure) + .def_readonly("structure_handle", &ps::PickResult::structureHandle) + .def_readonly("structure_type", &ps::PickResult::structureType) + .def_readonly("structure_name", &ps::PickResult::structureName) + .def_readonly("screen_coords", &ps::PickResult::screenCoords) + .def_readonly("buffer_inds", &ps::PickResult::bufferCoords) + .def_readonly("position", &ps::PickResult::position) + .def_readonly("depth", &ps::PickResult::depth) + .def_readonly("local_index", &ps::PickResult::localIndex) + ; + m.def("have_selection", [](){ return ps::pick::haveSelection();}); m.def("get_selection", [](){ const auto selection = ps::pick::getSelection(); @@ -530,6 +545,13 @@ PYBIND11_MODULE(polyscope_bindings, m) { return std::tuple(x[0], x[1], x[2], x[3]); }); + py::class_(m, "glm_ivec2"). + def(py::init()) + .def("as_tuple", + [](const glm::ivec2& x) { + return std::tuple(x[0], x[1]); + }); + py::class_(m, "glm_uvec3"). def(py::init()) .def("as_tuple", diff --git a/src/polyscope/core.py b/src/polyscope/core.py index 39a26dd..7e8c737 100644 --- a/src/polyscope/core.py +++ b/src/polyscope/core.py @@ -303,10 +303,25 @@ def have_selection(): return psb.have_selection() def get_selection(): - return psb.get_selection() + return PickResult(psb.get_selection()) + +class PickResult: + + def __init__(self, bound_pick_result): + + self.raw_result = bound_pick_result + + # translate most properties + self.is_hit = bound_pick_result.is_hit + self.structure_type_name = bound_pick_result.structure_type + self.structure_name = bound_pick_result.structure_name + self.screen_coords = bound_pick_result.screen_coords.as_tuple() + self.buffer_inds = bound_pick_result.buffer_inds.as_tuple() + self.position = np.array(bound_pick_result.position.as_tuple()) + self.depth = bound_pick_result.depth + self.local_index = bound_pick_result.local_index + -def set_selection(name, index): - psb.set_selection(name, index) ## Ground plane and shadows def set_ground_plane_mode(mode_str): From 525536d5f241e046f4aa3dea4ef94f2f1307b3c4 Mon Sep 17 00:00:00 2001 From: Nicholas Sharp Date: Thu, 20 Mar 2025 01:55:39 -0700 Subject: [PATCH 2/6] add pick resolvers for custom structure data --- deps/polyscope | 2 +- src/cpp/core.cpp | 80 ++++++++++++++++++---------------- src/cpp/curve_network.cpp | 11 ++++- src/cpp/point_cloud.cpp | 9 +++- src/cpp/surface_mesh.cpp | 12 ++++- src/cpp/volume_grid.cpp | 9 +++- src/cpp/volume_mesh.cpp | 9 +++- src/polyscope/core.py | 61 ++++++++++++++++++++++++-- src/polyscope/curve_network.py | 7 +++ src/polyscope/point_cloud.py | 3 ++ src/polyscope/surface_mesh.py | 10 ++++- src/polyscope/volume_grid.py | 8 +++- src/polyscope/volume_mesh.py | 10 ++++- 13 files changed, 181 insertions(+), 50 deletions(-) diff --git a/deps/polyscope b/deps/polyscope index f075418..14c21a4 160000 --- a/deps/polyscope +++ b/deps/polyscope @@ -1 +1 @@ -Subproject commit f07541805443269e1bba221d26febc0ae6de07f6 +Subproject commit 14c21a4fa7e6049dcdf71eb035237a6549a7a8f3 diff --git a/src/cpp/core.cpp b/src/cpp/core.cpp index 8b50fed..60be5a6 100644 --- a/src/cpp/core.cpp +++ b/src/cpp/core.cpp @@ -168,10 +168,10 @@ PYBIND11_MODULE(polyscope_bindings, m) { m.def("get_buffer_size", &ps::view::getBufferSize); m.def("set_window_resizable", &ps::view::setWindowResizable); m.def("get_window_resizable", &ps::view::getWindowResizable); - m.def("set_view_from_json", ps::view::setViewFromJson); - m.def("get_view_as_json", ps::view::getViewAsJson); - m.def("screen_coords_to_world_ray", ps::view::screenCoordsToWorldRay); - m.def("screen_coords_to_world_position", ps::view::screenCoordsToWorldPosition); + m.def("set_view_from_json", &ps::view::setViewFromJson); + m.def("get_view_as_json", &ps::view::getViewAsJson); + m.def("screen_coords_to_world_ray", &ps::view::screenCoordsToWorldRay); + m.def("screen_coords_to_world_position", &ps::view::screenCoordsToWorldPosition); m.def("set_background_color", [](glm::vec4 c) { for(int i = 0; i < 4; i++) ps::view::bgColor[i] = c[i]; }); m.def("get_background_color", []() { return glm2eigen(glm::vec4{ ps::view::bgColor[0], ps::view::bgColor[1], ps::view::bgColor[2], ps::view::bgColor[3] @@ -187,9 +187,9 @@ PYBIND11_MODULE(polyscope_bindings, m) { // === Messages m.def("info", overload_cast_()(&ps::info), "Send an info message"); - m.def("warning", ps::warning, "Send a warning message"); - m.def("error", ps::error, "Send an error message"); - m.def("terminating_error", ps::terminatingError, "Send a terminating error message"); + m.def("warning", &ps::warning, "Send a warning message"); + m.def("error", &ps::error, "Send an error message"); + m.def("terminating_error", &ps::terminatingError, "Send a terminating error message"); // === Callback m.def("set_user_callback", [](const std::function& func) { @@ -216,40 +216,21 @@ PYBIND11_MODULE(polyscope_bindings, m) { .def_readonly("structure_type", &ps::PickResult::structureType) .def_readonly("structure_name", &ps::PickResult::structureName) .def_readonly("screen_coords", &ps::PickResult::screenCoords) - .def_readonly("buffer_inds", &ps::PickResult::bufferCoords) + .def_readonly("buffer_inds", &ps::PickResult::bufferInds) .def_readonly("position", &ps::PickResult::position) .def_readonly("depth", &ps::PickResult::depth) .def_readonly("local_index", &ps::PickResult::localIndex) ; - m.def("have_selection", [](){ return ps::pick::haveSelection();}); - m.def("get_selection", [](){ - const auto selection = ps::pick::getSelection(); - const auto * structure = std::get<0>(selection); - if (structure == nullptr) { - return std::make_tuple(std::string(), size_t{0}); - } - return std::make_tuple(structure->name, std::get<1>(selection)); - }); - m.def( - "set_selection", - [](const std::string &name, size_t index){ - for(const auto &structureTypeName : std::array{ - ps::PointCloud::structureTypeName, - ps::CurveNetwork::structureTypeName, - ps::SurfaceMesh::structureTypeName, - ps::VolumeMesh::structureTypeName - }) { - if (ps::hasStructure(structureTypeName, name)) { - auto * structure = ps::getStructure(structureTypeName, name); - ps::pick::setSelection(std::make_pair(structure, index)); - break; - } - } - }, - py::arg("name"), - py::arg("index") - ); + // stateful selection + m.def("have_selection", &ps::haveSelection); + m.def("get_selection", &ps::getSelection); + m.def("reset_selection", &ps::resetSelection); + // inentionally no binding to set_selection(), it is low-level and not obvious how to bind + + // query what is under a pixel + m.def("query_pick_at_screen_coords", &ps::queryPickAtScreenCoords); + m.def("query_pick_at_buffer_inds", &ps::queryPickAtBufferInds); // === Ground plane and shadows m.def("set_ground_plane_mode", [](ps::GroundPlaneMode x) { ps::options::groundPlaneMode = x; }); @@ -468,6 +449,31 @@ PYBIND11_MODULE(polyscope_bindings, m) { .value("simple", ps::TransparencyMode::Simple) .value("pretty", ps::TransparencyMode::Pretty) .export_values(); + + py::enum_(m, "CurveNetworkElement") + .value("node", ps::CurveNetworkElement::NODE) + .value("edge", ps::CurveNetworkElement::EDGE) + .export_values(); + + py::enum_(m, "MeshElement") + .value("vertex", ps::MeshElement::VERTEX) + .value("face", ps::MeshElement::FACE) + .value("edge", ps::MeshElement::EDGE) + .value("halfedge", ps::MeshElement::HALFEDGE) + .value("corner", ps::MeshElement::CORNER) + .export_values(); + + py::enum_(m, "VolumeMeshElement") + .value("vertex", ps::VolumeMeshElement::VERTEX) + .value("edge", ps::VolumeMeshElement::EDGE) + .value("face", ps::VolumeMeshElement::FACE) + .value("cell", ps::VolumeMeshElement::CELL) + .export_values(); + + py::enum_(m, "VolumeGridElement") + .value("node", ps::VolumeGridElement::NODE) + .value("cell", ps::VolumeGridElement::CELL) + .export_values(); py::enum_(m, "PointRenderMode") .value("sphere", ps::PointRenderMode::Sphere) @@ -545,7 +551,7 @@ PYBIND11_MODULE(polyscope_bindings, m) { return std::tuple(x[0], x[1], x[2], x[3]); }); - py::class_(m, "glm_ivec2"). + py::class_(m, "glm_ivec2"). def(py::init()) .def("as_tuple", [](const glm::ivec2& x) { diff --git a/src/cpp/curve_network.cpp b/src/cpp/curve_network.cpp index 4392a91..80c5a93 100644 --- a/src/cpp/curve_network.cpp +++ b/src/cpp/curve_network.cpp @@ -16,7 +16,13 @@ namespace ps = polyscope; // clang-format off void bind_curve_network(py::module& m) { - // == Helper quantity classes + // == Helper classes + py::class_(m, "CurveNetworkPickResult") + .def(py::init<>()) + .def_readonly("element_type", &ps::CurveNetworkPickResult::elementType) + .def_readonly("index", &ps::CurveNetworkPickResult::index) + .def_readonly("t_edge", &ps::CurveNetworkPickResult::tEdge) + ; // Scalar quantities bindScalarQuantity(m, "CurveNetworkNodeScalarQuantity"); @@ -48,6 +54,9 @@ void bind_curve_network(py::module& m) { .def("set_material", &ps::CurveNetwork::setMaterial, "Set material") .def("get_material", &ps::CurveNetwork::getMaterial, "Get material") + // picking + .def("interpret_pick_result", &ps::CurveNetwork::interpretPickResult) + // quantities .def("add_node_color_quantity", &ps::CurveNetwork::addNodeColorQuantity, "Add a color function at nodes", py::arg("name"), py::arg("values"), py::return_value_policy::reference) diff --git a/src/cpp/point_cloud.cpp b/src/cpp/point_cloud.cpp index db6da9e..15b739d 100644 --- a/src/cpp/point_cloud.cpp +++ b/src/cpp/point_cloud.cpp @@ -20,7 +20,11 @@ using overload_cast_ = pybind11::detail::overload_cast_impl; // clang-format off void bind_point_cloud(py::module& m) { - // == Helper quantity classes + // == Helper classes + py::class_(m, "PointCloudPickResult") + .def(py::init<>()) + .def_readonly("index", &ps::PointCloudPickResult::index) + ; // Scalar quantities bindScalarQuantity(m, "PointCloudScalarQuantity"); @@ -50,6 +54,9 @@ void bind_point_cloud(py::module& m) { .def("set_point_render_mode", &ps::PointCloud::setPointRenderMode, "Set point render mode") .def("get_point_render_mode", &ps::PointCloud::getPointRenderMode, "Get point render mode") + // picking + .def("interpret_pick_result", &ps::PointCloud::interpretPickResult) + // variable radius .def("set_point_radius_quantity", overload_cast_()(&ps::PointCloud::setPointRadiusQuantity), diff --git a/src/cpp/surface_mesh.cpp b/src/cpp/surface_mesh.cpp index ae97ebf..3d35bdf 100644 --- a/src/cpp/surface_mesh.cpp +++ b/src/cpp/surface_mesh.cpp @@ -18,7 +18,14 @@ namespace ps = polyscope; void bind_surface_mesh(py::module& m) { - // == Helper quantity classes + // == Helper classes + py::class_(m, "SurfaceMeshPickResult") + .def(py::init<>()) + .def_readonly("element_type", &ps::SurfaceMeshPickResult::elementType) + .def_readonly("index", &ps::SurfaceMeshPickResult::index) + .def_readonly("bary_coords", &ps::SurfaceMeshPickResult::baryCoords) + ; + // Scalar quantities bindScalarQuantity(m, "SurfaceVertexScalarQuantity"); @@ -97,6 +104,9 @@ void bind_surface_mesh(py::module& m) { .def("get_back_face_policy", &ps::SurfaceMesh::getBackFacePolicy, "Get back face policy") .def("set_back_face_color", &ps::SurfaceMesh::setBackFaceColor, "Set back face color") .def("get_back_face_color", &ps::SurfaceMesh::getBackFaceColor, "Get back face color") + + // picking + .def("interpret_pick_result", &ps::SurfaceMesh::interpretPickResult) // permutations & bases .def("set_edge_permutation", &ps::SurfaceMesh::setEdgePermutation, "Set edge permutation") diff --git a/src/cpp/volume_grid.cpp b/src/cpp/volume_grid.cpp index 683bc48..a81584b 100644 --- a/src/cpp/volume_grid.cpp +++ b/src/cpp/volume_grid.cpp @@ -17,7 +17,12 @@ namespace ps = polyscope; void bind_volume_grid(py::module& m) { - // == Helper quantity classes + // == Helper classes + py::class_(m, "VolumeMeshPickResult") + .def(py::init<>()) + .def_readonly("element_type", &ps::VolumeGridPickResult::elementType) + .def_readonly("index", &ps::VolumeGridPickResult::index) + ; // Scalar quantities bindScalarQuantity(m, "VolumeGridNodeScalarQuantity") @@ -62,6 +67,8 @@ void bind_volume_grid(py::module& m) { .def("set_cube_size_factor", &ps::VolumeGrid::setCubeSizeFactor, "Set cube size factor") .def("get_cube_size_factor", &ps::VolumeGrid::getCubeSizeFactor, "Get cube size factor") + // picking + .def("interpret_pick_result", &ps::VolumeGrid::interpretPickResult) // = quantities diff --git a/src/cpp/volume_mesh.cpp b/src/cpp/volume_mesh.cpp index ada5d71..78781d1 100644 --- a/src/cpp/volume_mesh.cpp +++ b/src/cpp/volume_mesh.cpp @@ -16,7 +16,12 @@ namespace ps = polyscope; void bind_volume_mesh(py::module& m) { - // == Helper quantity classes + // == Helper classes + py::class_(m, "VolumeMeshPickResult") + .def(py::init<>()) + .def_readonly("element_type", &ps::VolumeMeshPickResult::elementType) + .def_readonly("index", &ps::VolumeMeshPickResult::index) + ; // Scalar quantities bindVMVScalarQuantity(m, "VolumeMeshVertexScalarQuantity"); @@ -52,6 +57,8 @@ void bind_volume_mesh(py::module& m) { .def("set_material", &ps::VolumeMesh::setMaterial, "Set material") .def("get_material", &ps::VolumeMesh::getMaterial, "Get material") + // picking + .def("interpret_pick_result", &ps::VolumeMesh::interpretPickResult) // = quantities diff --git a/src/polyscope/core.py b/src/polyscope/core.py index 7e8c737..8c7e5ea 100644 --- a/src/polyscope/core.py +++ b/src/polyscope/core.py @@ -1,6 +1,12 @@ import polyscope_bindings as psb import polyscope.imgui as psim +from polyscope.point_cloud import get_point_cloud +from polyscope.curve_network import get_curve_network +from polyscope.surface_mesh import get_surface_mesh +from polyscope.volume_mesh import get_volume_mesh +from polyscope.volume_grid import get_volume_grid + import os import numpy as np @@ -298,13 +304,23 @@ def set_user_callback(func): def clear_user_callback(): psb.clear_user_callback() -### Pick +### Picking + +def query_pick_at_screen_coords(screen_coords): + return PickResult(psb.query_pick_at_screen_coords(glm2(screen_coords))) + +def query_pick_at_buffer_inds(buffer_inds): + return PickResult(psb.query_pick_at_buffer_inds(glm2i(buffer_inds))) + def have_selection(): return psb.have_selection() def get_selection(): return PickResult(psb.get_selection()) +def reset_selection(): + psb.reset_selection() + class PickResult: def __init__(self, bound_pick_result): @@ -321,10 +337,34 @@ def __init__(self, bound_pick_result): self.depth = bound_pick_result.depth self.local_index = bound_pick_result.local_index + # additional per-structure data, such as barycentric coordinates + # if its a triangle in a mesh + self.structure_data = {} + + self.resolve_additional_data() + + def resolve_additional_data(self): + # resolve data from various types + + if self.structure_type_name == "PointCloud": + get_point_cloud(self.structure_name).append_pick_data(self) + + if self.structure_type_name == "CurveNetwork": + get_curve_network(self.structure_name).append_pick_data(self) + + if self.structure_type_name == "SurfaceMesh": + get_surface_mesh(self.structure_name).append_pick_data(self) + + if self.structure_type_name == "VolumeMesh": + get_volume_mesh(self.structure_name).append_pick_data(self) + + if self.structure_type_name == "VolumeGrid": + get_volume_grid(self.structure_name).append_pick_data(self) + ## Ground plane and shadows -def set_ground_plane_mode(mode_str): +def set_ground_plane_mode(mode_str):# psb.set_ground_plane_mode(str_to_ground_plane_mode(mode_str)) def set_ground_plane_height_mode(mode_str): @@ -541,6 +581,8 @@ def generate_camera_ray_corners(self): ## Small utilities def glm2(vals): return psb.glm_vec2(vals[0], vals[1]) +def glm2i(vals): + return psb.glm_ivec2(vals[0], vals[1]) def glm3u(vals): return psb.glm_uvec3(vals[0], vals[1], vals[2]) def glm3(vals): @@ -581,6 +623,19 @@ def load_color_map(cmap_name, filename): ## String-to-enum translation +# General case +# TODO: gradually replace the enum-specific methods below with this, +# ensuring each doesn't have any special breakage +def str_to_enum(s, enum): + if s in enum: return enum[s] + enum_val_names = [x.name for x in enum] + raise ValueError(f"Bad specifier '{s}' for {typename(enum)}, should be one of [{",".join(enum_val_names)}]") + +def enum_to_str(enum_val): + return enum_val.name + +## Per-enum maps + d_navigate = { "turntable" : psb.NavigateStyle.turntable, "free" : psb.NavigateStyle.free, @@ -777,7 +832,7 @@ def str_to_transparency_mode(s): } if s not in d: - raise ValueError("Bad transparenccy mode specifier '{}', should be one of [{}]".format(s, + raise ValueError("Bad transparency mode specifier '{}', should be one of [{}]".format(s, ",".join(["'{}'".format(x) for x in d.keys()]))) return d[s] diff --git a/src/polyscope/curve_network.py b/src/polyscope/curve_network.py index 3be899b..d25ac45 100644 --- a/src/polyscope/curve_network.py +++ b/src/polyscope/curve_network.py @@ -3,6 +3,7 @@ from polyscope.core import str_to_datatype, str_to_vectortype, glm3 from polyscope.structure import Structure from polyscope.common import process_quantity_args, process_scalar_args, process_color_args, process_vector_args, check_all_args_processed +from polyscope.core import str_to_enum, enum_to_str class CurveNetwork(Structure): @@ -89,6 +90,12 @@ def set_material(self, mat): def get_material(self): return self.bound_instance.get_material() + # Picking + def interpret_pick_result(self, pick_result): + struct_result = self.bound_instance.interpret_pick_result(pick_result) + pick_result.structure_data["element_type"] = enum_to_str(struct_result.element_type) + pick_result.structure_data["index"] = struct_result.index + pick_result.structure_data["t_edge"] = struct_result.t_edge ## Quantities diff --git a/src/polyscope/point_cloud.py b/src/polyscope/point_cloud.py index 6ce1792..127b110 100644 --- a/src/polyscope/point_cloud.py +++ b/src/polyscope/point_cloud.py @@ -89,6 +89,9 @@ def set_material(self, mat): def get_material(self): return self.bound_instance.get_material() + def interpret_pick_result(self, pick_result): + struct_result = self.bound_instance.interpret_pick_result(pick_result) + pick_result.structure_data["index"] = struct_result.index ## Quantities diff --git a/src/polyscope/surface_mesh.py b/src/polyscope/surface_mesh.py index c8118a7..7733d1f 100644 --- a/src/polyscope/surface_mesh.py +++ b/src/polyscope/surface_mesh.py @@ -3,7 +3,7 @@ from polyscope.core import str_to_datatype, str_to_vectortype, str_to_param_coords_type, \ str_to_param_viz_style, str_to_back_face_policy, back_face_policy_to_str,\ - str_to_image_origin, glm3 + str_to_image_origin, glm3, enum_to_str from polyscope.structure import Structure from polyscope.common import process_quantity_args, process_scalar_args, process_color_args, process_vector_args, process_texture_map_args, process_parameterization_args, check_all_args_processed, check_is_scalar_image, check_is_image3 @@ -82,6 +82,14 @@ def set_transparency_quantity(self, quantity_name): self.bound_instance.set_transparency_quantity(quantity_name) def clear_transparency_quantity(self): self.bound_instance.clear_transparency_quantity() + + + # Picking + def interpret_pick_result(self, pick_result): + struct_result = self.bound_instance.interpret_pick_result(pick_result) + pick_result.structure_data["element_type"] = enum_to_str(struct_result.element_type) + pick_result.structure_data["index"] = struct_result.index + pick_result.structure_data["bary_coords"] = struct_result.bary_coords ## Options diff --git a/src/polyscope/volume_grid.py b/src/polyscope/volume_grid.py index d1e44b4..d4087e4 100644 --- a/src/polyscope/volume_grid.py +++ b/src/polyscope/volume_grid.py @@ -1,7 +1,7 @@ import polyscope_bindings as psb import numpy as np -from polyscope.core import str_to_datatype, str_to_vectortype, str_to_param_coords_type, str_to_param_viz_style, glm3, glm3u +from polyscope.core import str_to_datatype, str_to_vectortype, str_to_param_coords_type, str_to_param_viz_style, glm3, glm3u, enum_to_str from polyscope.structure import Structure from polyscope.common import process_quantity_args, process_scalar_args, process_color_args, process_vector_args, check_all_args_processed, check_and_pop_arg @@ -114,6 +114,12 @@ def mark_cells_as_used(self): return self.bound_instance.mark_cells_as_used() + # Picking + def interpret_pick_result(self, pick_result): + struct_result = self.bound_instance.interpret_pick_result(pick_result) + pick_result.structure_data["element_type"] = enum_to_str(struct_result.element_type) + pick_result.structure_data["index"] = struct_result.index + ## Quantities # Scalar diff --git a/src/polyscope/volume_mesh.py b/src/polyscope/volume_mesh.py index f9eb284..0e5b59f 100644 --- a/src/polyscope/volume_mesh.py +++ b/src/polyscope/volume_mesh.py @@ -3,7 +3,7 @@ from polyscope.core import str_to_datatype, str_to_vectortype, str_to_param_coords_type, str_to_param_viz_style, glm3 from polyscope.structure import Structure -from polyscope.common import process_quantity_args, process_scalar_args, process_color_args, process_vector_args, check_all_args_processed +from polyscope.common import process_quantity_args, process_scalar_args, process_color_args, process_vector_args, check_all_args_processed, enum_to_str class VolumeMesh(Structure): @@ -82,7 +82,7 @@ def update_vertex_positions(self, vertices): ## Options - + # Color def set_color(self, val): self.bound_instance.set_color(glm3(val)) @@ -113,6 +113,12 @@ def set_material(self, mat): def get_material(self): return self.bound_instance.get_material() + # Picking + def interpret_pick_result(self, pick_result): + struct_result = self.bound_instance.interpret_pick_result(pick_result) + pick_result.structure_data["element_type"] = enum_to_str(struct_result.element_type) + pick_result.structure_data["index"] = struct_result.index + ## Quantities From f86039b86ef082facc2183fa7636e676ea80dbce Mon Sep 17 00:00:00 2001 From: Nicholas Sharp Date: Thu, 20 Mar 2025 18:03:37 -0700 Subject: [PATCH 3/6] clean up structure-specific selection --- src/cpp/volume_grid.cpp | 2 +- src/polyscope/core.py | 45 ++++++++++++++++++++-------------- src/polyscope/curve_network.py | 4 +-- src/polyscope/point_cloud.py | 4 +-- src/polyscope/surface_mesh.py | 8 +++--- src/polyscope/volume_grid.py | 4 +-- src/polyscope/volume_mesh.py | 8 +++--- test/polyscope_demo.py | 18 ++++++++++++++ 8 files changed, 61 insertions(+), 32 deletions(-) diff --git a/src/cpp/volume_grid.cpp b/src/cpp/volume_grid.cpp index a81584b..ea72501 100644 --- a/src/cpp/volume_grid.cpp +++ b/src/cpp/volume_grid.cpp @@ -18,7 +18,7 @@ namespace ps = polyscope; void bind_volume_grid(py::module& m) { // == Helper classes - py::class_(m, "VolumeMeshPickResult") + py::class_(m, "VolumeGridPickResult") .def(py::init<>()) .def_readonly("element_type", &ps::VolumeGridPickResult::elementType) .def_readonly("index", &ps::VolumeGridPickResult::index) diff --git a/src/polyscope/core.py b/src/polyscope/core.py index 8c7e5ea..240c99f 100644 --- a/src/polyscope/core.py +++ b/src/polyscope/core.py @@ -1,11 +1,7 @@ import polyscope_bindings as psb import polyscope.imgui as psim -from polyscope.point_cloud import get_point_cloud -from polyscope.curve_network import get_curve_network -from polyscope.surface_mesh import get_surface_mesh -from polyscope.volume_mesh import get_volume_mesh -from polyscope.volume_grid import get_volume_grid +import polyscope import os @@ -346,22 +342,35 @@ def __init__(self, bound_pick_result): def resolve_additional_data(self): # resolve data from various types - if self.structure_type_name == "PointCloud": - get_point_cloud(self.structure_name).append_pick_data(self) + if self.structure_type_name == "Point Cloud": + polyscope.point_cloud.get_point_cloud(self.structure_name).append_pick_data(self) - if self.structure_type_name == "CurveNetwork": - get_curve_network(self.structure_name).append_pick_data(self) + if self.structure_type_name == "Curve Network": + polyscope.curve_network.get_curve_network(self.structure_name).append_pick_data(self) - if self.structure_type_name == "SurfaceMesh": - get_surface_mesh(self.structure_name).append_pick_data(self) + if self.structure_type_name == "Surface Mesh": + polyscope.surface_mesh.get_surface_mesh(self.structure_name).append_pick_data(self) - if self.structure_type_name == "VolumeMesh": - get_volume_mesh(self.structure_name).append_pick_data(self) + if self.structure_type_name == "Volume Mesh": + polyscope.volume_mesh.get_volume_mesh(self.structure_name).append_pick_data(self) - if self.structure_type_name == "VolumeGrid": - get_volume_grid(self.structure_name).append_pick_data(self) - - + if self.structure_type_name == "Volume Grid": + polyscope.volume_grid.get_volume_grid(self.structure_name).append_pick_data(self) + + def __str__(self): + return f""" +PickResult( + is_hit={self.is_hit}, + structure_type_name={self.structure_type_name}, + structure_name={self.structure_name}, + screen_coords={self.screen_coords}, + buffer_inds={self.buffer_inds}, + position={self.position}, + depth={self.depth}, + local_index={self.local_index}, + structure_data={self.structure_data} +) +""" ## Ground plane and shadows def set_ground_plane_mode(mode_str):# @@ -629,7 +638,7 @@ def load_color_map(cmap_name, filename): def str_to_enum(s, enum): if s in enum: return enum[s] enum_val_names = [x.name for x in enum] - raise ValueError(f"Bad specifier '{s}' for {typename(enum)}, should be one of [{",".join(enum_val_names)}]") + raise ValueError(f"Bad specifier '{s}' for {typename(enum)}, should be one of [{','.join(enum_val_names)}]") def enum_to_str(enum_val): return enum_val.name diff --git a/src/polyscope/curve_network.py b/src/polyscope/curve_network.py index d25ac45..235db11 100644 --- a/src/polyscope/curve_network.py +++ b/src/polyscope/curve_network.py @@ -91,8 +91,8 @@ def get_material(self): return self.bound_instance.get_material() # Picking - def interpret_pick_result(self, pick_result): - struct_result = self.bound_instance.interpret_pick_result(pick_result) + def append_pick_data(self, pick_result): + struct_result = self.bound_instance.interpret_pick_result(pick_result.raw_result) pick_result.structure_data["element_type"] = enum_to_str(struct_result.element_type) pick_result.structure_data["index"] = struct_result.index pick_result.structure_data["t_edge"] = struct_result.t_edge diff --git a/src/polyscope/point_cloud.py b/src/polyscope/point_cloud.py index 127b110..c1fed35 100644 --- a/src/polyscope/point_cloud.py +++ b/src/polyscope/point_cloud.py @@ -89,8 +89,8 @@ def set_material(self, mat): def get_material(self): return self.bound_instance.get_material() - def interpret_pick_result(self, pick_result): - struct_result = self.bound_instance.interpret_pick_result(pick_result) + def append_pick_data(self, pick_result): + struct_result = self.bound_instance.interpret_pick_result(pick_result.raw_result) pick_result.structure_data["index"] = struct_result.index ## Quantities diff --git a/src/polyscope/surface_mesh.py b/src/polyscope/surface_mesh.py index 7733d1f..4211b3f 100644 --- a/src/polyscope/surface_mesh.py +++ b/src/polyscope/surface_mesh.py @@ -85,11 +85,13 @@ def clear_transparency_quantity(self): # Picking - def interpret_pick_result(self, pick_result): - struct_result = self.bound_instance.interpret_pick_result(pick_result) + def append_pick_data(self, pick_result): + struct_result = self.bound_instance.interpret_pick_result(pick_result.raw_result) pick_result.structure_data["element_type"] = enum_to_str(struct_result.element_type) pick_result.structure_data["index"] = struct_result.index - pick_result.structure_data["bary_coords"] = struct_result.bary_coords + bary_coords = np.array(struct_result.bary_coords.as_tuple()) + if not (bary_coords == np.array((-1,-1,-1))).all(): + pick_result.structure_data["bary_coords"] = bary_coords ## Options diff --git a/src/polyscope/volume_grid.py b/src/polyscope/volume_grid.py index d4087e4..50f2ca2 100644 --- a/src/polyscope/volume_grid.py +++ b/src/polyscope/volume_grid.py @@ -115,8 +115,8 @@ def mark_cells_as_used(self): # Picking - def interpret_pick_result(self, pick_result): - struct_result = self.bound_instance.interpret_pick_result(pick_result) + def append_pick_data(self, pick_result): + struct_result = self.bound_instance.interpret_pick_result(pick_result.raw_result) pick_result.structure_data["element_type"] = enum_to_str(struct_result.element_type) pick_result.structure_data["index"] = struct_result.index diff --git a/src/polyscope/volume_mesh.py b/src/polyscope/volume_mesh.py index 0e5b59f..fbbbd20 100644 --- a/src/polyscope/volume_mesh.py +++ b/src/polyscope/volume_mesh.py @@ -1,9 +1,9 @@ import polyscope_bindings as psb import numpy as np -from polyscope.core import str_to_datatype, str_to_vectortype, str_to_param_coords_type, str_to_param_viz_style, glm3 +from polyscope.core import str_to_datatype, str_to_vectortype, str_to_param_coords_type, str_to_param_viz_style, glm3, enum_to_str from polyscope.structure import Structure -from polyscope.common import process_quantity_args, process_scalar_args, process_color_args, process_vector_args, check_all_args_processed, enum_to_str +from polyscope.common import process_quantity_args, process_scalar_args, process_color_args, process_vector_args, check_all_args_processed class VolumeMesh(Structure): @@ -114,8 +114,8 @@ def get_material(self): return self.bound_instance.get_material() # Picking - def interpret_pick_result(self, pick_result): - struct_result = self.bound_instance.interpret_pick_result(pick_result) + def append_pick_data(self, pick_result): + struct_result = self.bound_instance.interpret_pick_result(pick_result.raw_result) pick_result.structure_data["element_type"] = enum_to_str(struct_result.element_type) pick_result.structure_data["index"] = struct_result.index diff --git a/test/polyscope_demo.py b/test/polyscope_demo.py index 7f88f2d..b69afea 100644 --- a/test/polyscope_demo.py +++ b/test/polyscope_demo.py @@ -32,6 +32,7 @@ def color_func(pts): A[:,0] = np.cos(3*pts[:,0])**2 return A +is_test_clicking = False def main(): @@ -56,11 +57,28 @@ def my_function(): def callback(): # Executed every frame + global is_test_clicking + + if is_test_clicking: + if(psim.Button("Cancel")): + is_test_clicking = False + + io = psim.GetIO() + if io.MouseClicked[0]: + screen_coords = io.MousePos + pick_result = polyscope.query_pick_at_screen_coords(screen_coords) + print(pick_result) + is_test_clicking = False + if(psim.Button("Test button")): my_function() implicit_ui() + if(psim.Button("Test pick")): + is_test_clicking = True + + polyscope.set_user_callback(callback) From 06bb0f42713fd6b2fc4c4115b5892ae6e201d570 Mon Sep 17 00:00:00 2001 From: Nicholas Sharp Date: Fri, 21 Mar 2025 01:35:24 -0700 Subject: [PATCH 4/6] bind selection mode, drop removed function --- src/cpp/core.cpp | 7 ++++++- src/cpp/surface_mesh.cpp | 2 ++ src/polyscope/core.py | 4 +++- src/polyscope/surface_mesh.py | 6 ++++++ test/polyscope_test.py | 6 ++++++ 5 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/cpp/core.cpp b/src/cpp/core.cpp index 60be5a6..a3963e4 100644 --- a/src/cpp/core.cpp +++ b/src/cpp/core.cpp @@ -171,7 +171,6 @@ PYBIND11_MODULE(polyscope_bindings, m) { m.def("set_view_from_json", &ps::view::setViewFromJson); m.def("get_view_as_json", &ps::view::getViewAsJson); m.def("screen_coords_to_world_ray", &ps::view::screenCoordsToWorldRay); - m.def("screen_coords_to_world_position", &ps::view::screenCoordsToWorldPosition); m.def("set_background_color", [](glm::vec4 c) { for(int i = 0; i < 4; i++) ps::view::bgColor[i] = c[i]; }); m.def("get_background_color", []() { return glm2eigen(glm::vec4{ ps::view::bgColor[0], ps::view::bgColor[1], ps::view::bgColor[2], ps::view::bgColor[3] @@ -463,6 +462,12 @@ PYBIND11_MODULE(polyscope_bindings, m) { .value("corner", ps::MeshElement::CORNER) .export_values(); + py::enum_(m, "MeshSelectionMode") + .value("auto", ps::MeshSelectionMode::Auto) + .value("vertices_only", ps::MeshSelectionMode::VerticesOnly) + .value("faces_only", ps::MeshSelectionMode::FacesOnly) + .export_values(); + py::enum_(m, "VolumeMeshElement") .value("vertex", ps::VolumeMeshElement::VERTEX) .value("edge", ps::VolumeMeshElement::EDGE) diff --git a/src/cpp/surface_mesh.cpp b/src/cpp/surface_mesh.cpp index 3d35bdf..a70060f 100644 --- a/src/cpp/surface_mesh.cpp +++ b/src/cpp/surface_mesh.cpp @@ -98,6 +98,8 @@ void bind_surface_mesh(py::module& m) { .def("get_smooth_shade", &ps::SurfaceMesh::isSmoothShade, "Get if smooth shading is enabled") .def("set_shade_style", &ps::SurfaceMesh::setShadeStyle, "Set shading") .def("get_shade_style", &ps::SurfaceMesh::getShadeStyle, "Get shading") + .def("set_selection_mode", &ps::SurfaceMesh::setSelectionMode) + .def("get_selection_mode", &ps::SurfaceMesh::getSelectionMode) .def("set_material", &ps::SurfaceMesh::setMaterial, "Set material") .def("get_material", &ps::SurfaceMesh::getMaterial, "Get material") .def("set_back_face_policy", &ps::SurfaceMesh::setBackFacePolicy, "Set back face policy") diff --git a/src/polyscope/core.py b/src/polyscope/core.py index 240c99f..54247d2 100644 --- a/src/polyscope/core.py +++ b/src/polyscope/core.py @@ -235,8 +235,10 @@ def get_view_as_json(): def screen_coords_to_world_ray(screen_coords): return np.array(psb.screen_coords_to_world_ray(glm2(screen_coords)).as_tuple()) +# deprecated! use query_pick_at_screen_coords def screen_coords_to_world_position(screen_coords): - return np.array(psb.screen_coords_to_world_position(glm2(screen_coords)).as_tuple()) + pick_result = query_pick_at_screen_coords(screen_coords) + return pick_result.position def set_background_color(c): if len(c) == 3: c = (c[0], c[1], c[2], 1.0) diff --git a/src/polyscope/surface_mesh.py b/src/polyscope/surface_mesh.py index 4211b3f..cae5ab4 100644 --- a/src/polyscope/surface_mesh.py +++ b/src/polyscope/surface_mesh.py @@ -120,6 +120,12 @@ def set_smooth_shade(self, val): def get_smooth_shade(self): return self.bound_instance.get_smooth_shade() + # Selection Mode + def set_selection_mode(self, val): + self.bound_instance.set_selection_mode(val) + def get_selection_mode(self): + return self.bound_instance.get_selection_mode() + # Material def set_material(self, mat): self.bound_instance.set_material(mat) diff --git a/test/polyscope_test.py b/test/polyscope_test.py index 5e572f0..cfe6fda 100644 --- a/test/polyscope_test.py +++ b/test/polyscope_test.py @@ -1138,6 +1138,12 @@ def test_options(self): p.set_edge_width(1.5) ps.show(3) self.assertAlmostEqual(p.get_edge_width(), 1.5) + + # Selection mode + p.set_selection_mode('auto') + p.set_selection_mode('vertices_only') + p.set_selection_mode('faces_only') + ps.show(3) # Material p.set_material("candy") From 24837926ad2d3529bee8bcdb5e02b976ea744781 Mon Sep 17 00:00:00 2001 From: Nicholas Sharp Date: Fri, 21 Mar 2025 02:27:49 -0700 Subject: [PATCH 5/6] rename pick functions, fix enums --- deps/polyscope | 2 +- src/cpp/core.cpp | 54 +++++++++++++++++------------------ src/polyscope/core.py | 23 +++++++++------ src/polyscope/surface_mesh.py | 6 ++-- test/polyscope_demo.py | 2 +- test/polyscope_test.py | 8 ++++++ 6 files changed, 55 insertions(+), 40 deletions(-) diff --git a/deps/polyscope b/deps/polyscope index 14c21a4..0dd0420 160000 --- a/deps/polyscope +++ b/deps/polyscope @@ -1 +1 @@ -Subproject commit 14c21a4fa7e6049dcdf71eb035237a6549a7a8f3 +Subproject commit 0dd042088dc8c988d134e2c6e83be0391623cbac diff --git a/src/cpp/core.cpp b/src/cpp/core.cpp index a3963e4..4ab211e 100644 --- a/src/cpp/core.cpp +++ b/src/cpp/core.cpp @@ -228,8 +228,8 @@ PYBIND11_MODULE(polyscope_bindings, m) { // inentionally no binding to set_selection(), it is low-level and not obvious how to bind // query what is under a pixel - m.def("query_pick_at_screen_coords", &ps::queryPickAtScreenCoords); - m.def("query_pick_at_buffer_inds", &ps::queryPickAtBufferInds); + m.def("pick_at_screen_coords", &ps::pickAtScreenCoords); + m.def("pick_at_buffer_inds", &ps::pickAtBufferInds); // === Ground plane and shadows m.def("set_ground_plane_mode", [](ps::GroundPlaneMode x) { ps::options::groundPlaneMode = x; }); @@ -374,12 +374,12 @@ PYBIND11_MODULE(polyscope_bindings, m) { .value("arcball", ps::view::NavigateStyle::Arcball) .value("none", ps::view::NavigateStyle::None) .value("first_person", ps::view::NavigateStyle::FirstPerson) - .export_values(); + ; py::enum_(m, "ProjectionMode") .value("perspective", ps::ProjectionMode::Perspective) .value("orthographic", ps::ProjectionMode::Orthographic) - .export_values(); + ; py::enum_(m, "UpDir") .value("x_up", ps::UpDir::XUp) @@ -388,7 +388,7 @@ PYBIND11_MODULE(polyscope_bindings, m) { .value("neg_x_up", ps::UpDir::NegXUp) .value("neg_y_up", ps::UpDir::NegYUp) .value("neg_z_up", ps::UpDir::NegZUp) - .export_values(); + ; py::enum_(m, "FrontDir") .value("x_front", ps::FrontDir::XFront) @@ -397,24 +397,24 @@ PYBIND11_MODULE(polyscope_bindings, m) { .value("neg_x_front", ps::FrontDir::NegXFront) .value("neg_y_front", ps::FrontDir::NegYFront) .value("neg_z_front", ps::FrontDir::NegZFront) - .export_values(); + ; py::enum_(m, "DataType") .value("standard", ps::DataType::STANDARD) .value("symmetric", ps::DataType::SYMMETRIC) .value("magnitude", ps::DataType::MAGNITUDE) .value("categorical", ps::DataType::CATEGORICAL) - .export_values(); + ; py::enum_(m, "VectorType") .value("standard", ps::VectorType::STANDARD) .value("ambient", ps::VectorType::AMBIENT) - .export_values(); + ; py::enum_(m, "ParamCoordsType") .value("unit", ps::ParamCoordsType::UNIT) .value("world", ps::ParamCoordsType::WORLD) - .export_values(); + ; py::enum_(m, "ParamVizStyle") .value("checker", ps::ParamVizStyle::CHECKER) @@ -422,37 +422,37 @@ PYBIND11_MODULE(polyscope_bindings, m) { .value("grid", ps::ParamVizStyle::GRID) .value("local_check", ps::ParamVizStyle::LOCAL_CHECK) .value("local_rad", ps::ParamVizStyle::LOCAL_RAD) - .export_values(); + ; py::enum_(m, "BackFacePolicy") .value("identical", ps::BackFacePolicy::Identical) .value("different", ps::BackFacePolicy::Different) .value("custom", ps::BackFacePolicy::Custom) .value("cull", ps::BackFacePolicy::Cull) - .export_values(); + ; py::enum_(m, "GroundPlaneMode") .value("none", ps::GroundPlaneMode::None) .value("tile", ps::GroundPlaneMode::Tile) .value("tile_reflection", ps::GroundPlaneMode::TileReflection) .value("shadow_only", ps::GroundPlaneMode::ShadowOnly) - .export_values(); + ; py::enum_(m, "GroundPlaneHeightMode") .value("automatic", ps::GroundPlaneHeightMode::Automatic) .value("manual", ps::GroundPlaneHeightMode::Manual) - .export_values(); + ; py::enum_(m, "TransparencyMode") .value("none", ps::TransparencyMode::None) .value("simple", ps::TransparencyMode::Simple) .value("pretty", ps::TransparencyMode::Pretty) - .export_values(); + ; py::enum_(m, "CurveNetworkElement") .value("node", ps::CurveNetworkElement::NODE) .value("edge", ps::CurveNetworkElement::EDGE) - .export_values(); + ; py::enum_(m, "MeshElement") .value("vertex", ps::MeshElement::VERTEX) @@ -460,56 +460,56 @@ PYBIND11_MODULE(polyscope_bindings, m) { .value("edge", ps::MeshElement::EDGE) .value("halfedge", ps::MeshElement::HALFEDGE) .value("corner", ps::MeshElement::CORNER) - .export_values(); + ; py::enum_(m, "MeshSelectionMode") .value("auto", ps::MeshSelectionMode::Auto) .value("vertices_only", ps::MeshSelectionMode::VerticesOnly) .value("faces_only", ps::MeshSelectionMode::FacesOnly) - .export_values(); + ; py::enum_(m, "VolumeMeshElement") .value("vertex", ps::VolumeMeshElement::VERTEX) .value("edge", ps::VolumeMeshElement::EDGE) .value("face", ps::VolumeMeshElement::FACE) .value("cell", ps::VolumeMeshElement::CELL) - .export_values(); + ; py::enum_(m, "VolumeGridElement") .value("node", ps::VolumeGridElement::NODE) .value("cell", ps::VolumeGridElement::CELL) - .export_values(); + ; py::enum_(m, "PointRenderMode") .value("sphere", ps::PointRenderMode::Sphere) .value("quad", ps::PointRenderMode::Quad) - .export_values(); + ; py::enum_(m, "FilterMode") .value("linear", ps::FilterMode::Linear) .value("nearest", ps::FilterMode::Nearest) - .export_values(); + ; py::enum_(m, "ImageOrigin") .value("lower_left", ps::ImageOrigin::LowerLeft) .value("upper_left", ps::ImageOrigin::UpperLeft) - .export_values(); + ; py::enum_(m, "MeshShadeStyle") .value("smooth", ps::MeshShadeStyle::Smooth) .value("flat", ps::MeshShadeStyle::Flat) .value("tri_flat", ps::MeshShadeStyle::TriFlat) - .export_values(); + ; py::enum_(m, "IsolineStyle") .value("stripe", ps::IsolineStyle::Stripe) .value("contour", ps::IsolineStyle::Contour) - .export_values(); + ; py::enum_(m, "ImplicitRenderMode") .value("sphere_march", ps::ImplicitRenderMode::SphereMarch) .value("fixed_step", ps::ImplicitRenderMode::FixedStep) - .export_values(); + ; py::enum_(m, "ManagedBufferType") .value(ps::typeName(ps::ManagedBufferType::Float ).c_str(), ps::ManagedBufferType::Float ) @@ -525,14 +525,14 @@ PYBIND11_MODULE(polyscope_bindings, m) { .value(ps::typeName(ps::ManagedBufferType::UVec2 ).c_str(), ps::ManagedBufferType::UVec2 ) .value(ps::typeName(ps::ManagedBufferType::UVec3 ).c_str(), ps::ManagedBufferType::UVec3 ) .value(ps::typeName(ps::ManagedBufferType::UVec4 ).c_str(), ps::ManagedBufferType::UVec4 ) - .export_values(); + ; py::enum_(m, "DeviceBufferType") .value("attribute", ps::DeviceBufferType::Attribute) .value("texture1d", ps::DeviceBufferType::Texture1d) .value("texture2d", ps::DeviceBufferType::Texture2d) .value("texture3d", ps::DeviceBufferType::Texture3d) - .export_values(); + ; // === Mini bindings for a little bit of glm py::class_(m, "glm_vec2"). diff --git a/src/polyscope/core.py b/src/polyscope/core.py index 54247d2..bca4a62 100644 --- a/src/polyscope/core.py +++ b/src/polyscope/core.py @@ -237,7 +237,7 @@ def screen_coords_to_world_ray(screen_coords): # deprecated! use query_pick_at_screen_coords def screen_coords_to_world_position(screen_coords): - pick_result = query_pick_at_screen_coords(screen_coords) + pick_result = pick(screen_coords=screen_coords) return pick_result.position def set_background_color(c): @@ -304,11 +304,18 @@ def clear_user_callback(): ### Picking -def query_pick_at_screen_coords(screen_coords): - return PickResult(psb.query_pick_at_screen_coords(glm2(screen_coords))) +def pick(*, screen_coords=None, buffer_inds=None): + if(screen_coords is not None and buffer_inds is not None): + raise ValueError("pass args one of screen_coords OR buffer_inds, but not both") + if(screen_coords is None and buffer_inds is None): + raise ValueError("must pass args one of screen_coords or buffer_inds") -def query_pick_at_buffer_inds(buffer_inds): - return PickResult(psb.query_pick_at_buffer_inds(glm2i(buffer_inds))) + if(screen_coords is not None): + raw_result = psb.pick_at_screen_coords(glm2(screen_coords)) + if(buffer_inds is not None): + raw_result = psb.pick_at_buffer_inds(glm2i(buffer_inds)) + + return PickResult(raw_result) def have_selection(): return psb.have_selection() @@ -638,9 +645,9 @@ def load_color_map(cmap_name, filename): # TODO: gradually replace the enum-specific methods below with this, # ensuring each doesn't have any special breakage def str_to_enum(s, enum): - if s in enum: return enum[s] - enum_val_names = [x.name for x in enum] - raise ValueError(f"Bad specifier '{s}' for {typename(enum)}, should be one of [{','.join(enum_val_names)}]") + if s in enum.__members__: return enum.__members__[s] + enum_val_names = [x for x in enum.__members__] + raise ValueError(f"Bad specifier '{s}' for {enum.__name__}, should be one of [{','.join(enum_val_names)}]") def enum_to_str(enum_val): return enum_val.name diff --git a/src/polyscope/surface_mesh.py b/src/polyscope/surface_mesh.py index cae5ab4..b0c8466 100644 --- a/src/polyscope/surface_mesh.py +++ b/src/polyscope/surface_mesh.py @@ -3,7 +3,7 @@ from polyscope.core import str_to_datatype, str_to_vectortype, str_to_param_coords_type, \ str_to_param_viz_style, str_to_back_face_policy, back_face_policy_to_str,\ - str_to_image_origin, glm3, enum_to_str + str_to_image_origin, glm3, enum_to_str, str_to_enum from polyscope.structure import Structure from polyscope.common import process_quantity_args, process_scalar_args, process_color_args, process_vector_args, process_texture_map_args, process_parameterization_args, check_all_args_processed, check_is_scalar_image, check_is_image3 @@ -122,9 +122,9 @@ def get_smooth_shade(self): # Selection Mode def set_selection_mode(self, val): - self.bound_instance.set_selection_mode(val) + self.bound_instance.set_selection_mode(str_to_enum(val, psb.MeshSelectionMode)) def get_selection_mode(self): - return self.bound_instance.get_selection_mode() + return enum_to_str(self.bound_instance.get_selection_mode()) # Material def set_material(self, mat): diff --git a/test/polyscope_demo.py b/test/polyscope_demo.py index b69afea..70c0723 100644 --- a/test/polyscope_demo.py +++ b/test/polyscope_demo.py @@ -66,7 +66,7 @@ def callback(): io = psim.GetIO() if io.MouseClicked[0]: screen_coords = io.MousePos - pick_result = polyscope.query_pick_at_screen_coords(screen_coords) + pick_result = polyscope.pick(screen_coords=screen_coords) print(pick_result) is_test_clicking = False diff --git a/test/polyscope_test.py b/test/polyscope_test.py index cfe6fda..856d8ce 100644 --- a/test/polyscope_test.py +++ b/test/polyscope_test.py @@ -237,6 +237,14 @@ def test_screenshot(self): self.assertEqual(buff.shape, (h,w,4)) ps.show(3) + + + def test_picking(self): + + res = ps.pick(buffer_inds=(77,88)) + res = ps.pick(screen_coords=(0.78,.96)) + + ps.show(3) def test_slice_plane(self): From dbb339d6078dbeb600599689a3d7ddac77a5456a Mon Sep 17 00:00:00 2001 From: Nicholas Sharp Date: Tue, 1 Apr 2025 02:03:02 -0700 Subject: [PATCH 6/6] update dep to latest --- deps/polyscope | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/polyscope b/deps/polyscope index 0dd0420..c159e57 160000 --- a/deps/polyscope +++ b/deps/polyscope @@ -1 +1 @@ -Subproject commit 0dd042088dc8c988d134e2c6e83be0391623cbac +Subproject commit c159e571e73aa7b05138ccdcc2090c23e0f2fb9f