Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions src/cpp/core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,37 @@ PYBIND11_MODULE(polyscope_bindings, m) {
m.def("add_scene_slice_plane", ps::addSceneSlicePlane, "add a slice plane", py::return_value_policy::reference);
m.def("remove_last_scene_slice_plane", ps::removeLastSceneSlicePlane, "remove last scene plane");

// === Transformation Gizmos

py::class_<ps::TransformationGizmo>(m, "TransformationGizmo")
.def(py::init<std::string>())
.def_readonly("name", &ps::TransformationGizmo::name)
.def("remove", &ps::TransformationGizmo::remove, "remove")
.def("set_enabled", &ps::TransformationGizmo::setEnabled, "set enabled")
.def("get_enabled", &ps::TransformationGizmo::getEnabled, "get enabled")
.def("set_transform", [] (ps::TransformationGizmo& g, const Eigen::Matrix4d& T) { g.setTransform(eigen2glm(T)); }, "set transform")
.def("get_transform", [](ps::TransformationGizmo& g) { return glm2eigen(g.getTransform()); }, "get transform")
.def("set_position", &ps::TransformationGizmo::setPosition, "set position")
.def("get_position", [](ps::TransformationGizmo& g) { return glm2eigen(g.getPosition()); }, "get position")
.def("set_allow_translation", &ps::TransformationGizmo::setAllowTranslation, "set allow translation")
.def("get_allow_translation", &ps::TransformationGizmo::getAllowTranslation, "get allow translation")
.def("set_allow_rotation", &ps::TransformationGizmo::setAllowRotation, "set allow rotation")
.def("get_allow_rotation", &ps::TransformationGizmo::getAllowRotation, "get allow rotation")
.def("set_allow_scaling", &ps::TransformationGizmo::setAllowScaling, "set allow scaling")
.def("get_allow_scaling", &ps::TransformationGizmo::getAllowScaling, "get allow scaling")
.def("get_interact_in_local_space", &ps::TransformationGizmo::getInteractInLocalSpace, "get interact in local space")
.def("set_interact_in_local_space", &ps::TransformationGizmo::setInteractInLocalSpace, "set interact in local space")
.def("get_gizmo_size", &ps::TransformationGizmo::getGizmoSize, "get gizmo size")
.def("set_gizmo_size", &ps::TransformationGizmo::setGizmoSize, "set gizmo size")
.def("build_inline_transform_ui", &ps::TransformationGizmo::buildInlineTransformUI, "build inline transform UI")
;

m.def("add_transformation_gizmo", [](std::string name) {return ps::addTransformationGizmo(name); }, "add a transformation gizmo", py::return_value_policy::reference);
m.def("get_transformation_gizmo", &ps::getTransformationGizmo, "get a transformation gizmo", py::return_value_policy::reference);
m.def("remove_transformation_gizmo", overload_cast_<std::string>()(&ps::removeTransformationGizmo), "remove a transformation gizmo by name");
m.def("remove_transformation_gizmo", overload_cast_<ps::TransformationGizmo*>()(&ps::removeTransformationGizmo), "remove a transformation gizmo by ptr");
m.def("remove_all_transformation_gizmos", &ps::removeAllTransformationGizmos, "remove all transformation gizmos");

// === Camera Parameters
py::class_<ps::CameraIntrinsics>(m, "CameraIntrinsics")
.def(py::init<>())
Expand Down
1 change: 1 addition & 0 deletions src/cpp/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ py::class_<StructureT> bindStructure(py::module& m, std::string name) {
.def("get_position", [](StructureT& s) { return glm2eigen(s.getPosition()); }, "get the position of the shape origin after transform")
.def("set_transform_gizmo_enabled", &StructureT::setTransformGizmoEnabled)
.def("get_transform_gizmo_enabled", &StructureT::getTransformGizmoEnabled)
.def("get_transformation_gizmo", &StructureT::getTransformGizmo, py::return_value_policy::reference, "Get the TransformationGizmo associated with this structure")

// floating quantites
.def("add_scalar_image_quantity", &StructureT::template addScalarImageQuantity<Eigen::VectorXf>, py::arg("name"), py::arg("dimX"), py::arg("dimY"), py::arg("values"), py::arg("imageOrigin")=ps::ImageOrigin::UpperLeft, py::arg("type")=ps::DataType::STANDARD, py::return_value_policy::reference)
Expand Down
92 changes: 92 additions & 0 deletions src/polyscope/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,98 @@ def remove_last_scene_slice_plane():
# deprecated
psb.remove_last_scene_slice_plane()

## Transformation Gizmo

class TransformationGizmo:
# This class wraps a _reference_ to the underlying object, whose lifetime is managed by Polyscope

# End users should not call this constrctor, use add_transformation_gizmo() instead
def __init__(self, instance):

# Wrap an existing instance
self.bound_gizmo = instance

def get_name(self):
return self.bound_gizmo.name

def remove(self):
self.bound_gizmo.remove()

def set_enabled(self, val):
self.bound_gizmo.set_enabled(val)

def get_enabled(self):
return self.bound_gizmo.get_enabled()

def set_transform(self, T):
if not isinstance(T, np.ndarray) or T.shape != (4, 4):
raise ValueError("T should be a 4x4 numpy matrix")
self.bound_gizmo.set_transform(T)

def get_transform(self):
return self.bound_gizmo.get_transform()

def set_position(self, p):
self.bound_gizmo.set_position(glm3(p))

def get_position(self):
return self.bound_gizmo.get_position()

def set_allow_translation(self, val):
self.bound_gizmo.set_allow_translation(val)

def get_allow_translation(self):
return self.bound_gizmo.get_allow_translation()

def set_allow_rotation(self, val):
self.bound_gizmo.set_allow_rotation(val)

def get_allow_rotation(self):
return self.bound_gizmo.get_allow_rotation()

def set_allow_scaling(self, val):
self.bound_gizmo.set_allow_scaling(val)

def get_allow_scaling(self):
return self.bound_gizmo.get_allow_scaling()

def get_interact_in_local_space(self):
return self.bound_gizmo.get_interact_in_local_space()

def set_interact_in_local_space(self, val):
self.bound_gizmo.set_interact_in_local_space(val)

def get_gizmo_scale(self):
# underlying binding uses "size"
return self.bound_gizmo.get_gizmo_size()

def set_gizmo_scale(self, val):
# underlying binding uses "size"
self.bound_gizmo.set_gizmo_size(float(val))

def build_inline_transform_ui(self):
self.bound_gizmo.build_inline_transform_ui()

def add_transformation_gizmo(name=None):
if name is None:
# name gets automatically set internally; pass empty string
instance = psb.add_transformation_gizmo("")
else:
instance = psb.add_transformation_gizmo(name)

return TransformationGizmo(instance)

def get_transformation_gizmo(name):
instance = psb.get_transformation_gizmo(name)
return TransformationGizmo(instance)

def remove_transformation_gizmo(name):
psb.remove_transformation_gizmo(name)

def remove_all_transformation_gizmos():
psb.remove_all_transformation_gizmos()


### Camera Parameters

class CameraIntrinsics:
Expand Down
3 changes: 3 additions & 0 deletions src/polyscope/structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from polyscope.floating_quantities import add_scalar_image_quantity, add_color_image_quantity, add_color_alpha_image_quantity, add_depth_render_image_quantity, add_color_render_image_quantity, add_scalar_render_image_quantity, add_raw_color_render_image_quantity, add_raw_color_alpha_render_image_quantity
from polyscope.managed_buffer import ManagedBuffer
from polyscope.core import TransformationGizmo

# Base class for common properties and methods on structures
class Structure:
Expand Down Expand Up @@ -62,6 +63,8 @@ def set_transform_gizmo_enabled(self, val):
self.bound_instance.set_transform_gizmo_enabled(val)
def get_transform_gizmo_enabled(self):
return self.bound_instance.get_transform_gizmo_enabled()
def get_transformation_gizmo(self):
return TransformationGizmo(self.bound_instance.get_transformation_gizmo())

## Managed Buffers

Expand Down
87 changes: 87 additions & 0 deletions test/polyscope_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,93 @@ def test_slice_plane(self):
ps.add_slice_plane("test2")
ps.remove_all_slice_planes()

def test_transformation_gizmo(self):

# Create a gizmo
g1 = ps.add_transformation_gizmo("gizmo_1")
self.assertEqual(g1.get_name(), "gizmo_1")

# Enable/disable
g1.set_enabled(True)
self.assertEqual(True, g1.get_enabled())
g1.set_enabled(False)
self.assertEqual(False, g1.get_enabled())

# Set/get transform
T_I = np.eye(4)
g1.set_transform(T_I)
T_ret = g1.get_transform()
self.assertTrue(isinstance(T_ret, np.ndarray))
self.assertEqual(T_ret.shape, (4,4))
self.assertTrue(np.allclose(T_ret, T_I))

T2 = np.array([
[1., 0., 0., 3.],
[0., 0., -1., -2.],
[0., 1., 0., 5.],
[0., 0., 0., 1.]
])
g1.set_transform(T2)
self.assertTrue(np.allclose(g1.get_transform(), T2))

# Get/set position
g1.set_position(np.array((1.0, 2.0, 3.0)))
self.assertTrue(np.allclose(g1.get_position(), np.array((1.0, 2.0, 3.0))))

# Allow toggles
g1.set_allow_translation(True)
self.assertEqual(True, g1.get_allow_translation())
g1.set_allow_translation(False)
self.assertEqual(False, g1.get_allow_translation())

g1.set_allow_rotation(True)
self.assertEqual(True, g1.get_allow_rotation())
g1.set_allow_rotation(False)
self.assertEqual(False, g1.get_allow_rotation())

g1.set_allow_scaling(True)
self.assertEqual(True, g1.get_allow_scaling())
g1.set_allow_scaling(False)
self.assertEqual(False, g1.get_allow_scaling())

# Local-space interaction toggle
g1.set_interact_in_local_space(True)
self.assertEqual(True, g1.get_interact_in_local_space())
g1.set_interact_in_local_space(False)
self.assertEqual(False, g1.get_interact_in_local_space())

# Gizmo size (scale) getter/setter
g1.set_gizmo_scale(0.75)
self.assertAlmostEqual(0.75, g1.get_gizmo_scale())

# Retrieve by name
g1b = ps.get_transformation_gizmo("gizmo_1")
self.assertEqual(g1b.get_name(), "gizmo_1")

ps.show(3)

# Remove by name
ps.remove_transformation_gizmo("gizmo_1")

# Create another and remove via instance method
g2 = ps.add_transformation_gizmo("gizmo_2")
self.assertEqual(g2.get_name(), "gizmo_2")
g2.remove()

# Add with auto-naming
ps.add_transformation_gizmo()
ps.add_transformation_gizmo()

# Add a couple and clear all
ps.add_transformation_gizmo("gizmo_B")
ps.remove_all_transformation_gizmos()

# Get the reference for a structure
pt_cloud_0 = ps.register_point_cloud("cloud0", np.zeros((10,3)))
gizmo = pt_cloud_0.get_transformation_gizmo()
self.assertIsInstance(gizmo, ps.TransformationGizmo)
gizmo.set_allow_rotation(False)
ps.remove_all_structures()

def test_load_material(self):

Expand Down
Loading