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
49 changes: 46 additions & 3 deletions examples/demo.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,9 @@
},
{
"cell_type": "markdown",
"metadata": {},
"metadata": {
"tags": []
},
"source": [
"## Cart-Pole\n",
"\n",
Expand Down Expand Up @@ -453,6 +455,47 @@
" time.sleep(0.01)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's set the camera position to above left of the cartpole:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"vis.jupyter_cell()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"vis.set_cam_pos([0.6, -1.0, 1.0])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's change the focus to the leftmost 'l' character:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"vis.set_cam_target([0.0, -1.0, 0.0])"
]
},
{
"cell_type": "code",
"execution_count": null,
Expand All @@ -477,9 +520,9 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.5.2"
"version": "3.9.13"
}
},
"nbformat": 4,
"nbformat_minor": 2
"nbformat_minor": 4
}
26 changes: 25 additions & 1 deletion src/meshcat/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,36 @@ def lower(self):
u"matrix": list(self.matrix.T.flatten())
}

class CaptureImage:

class SetCamTarget:
"""Set the camera target point."""
__slots__ = ["value"]
def __init__(self, pos):
self.value = pos

def lower(self):
return {
u"type": "set_target",
u"path": "",
u"value": list(self.value)
}


class CaptureImage:

def __init__(self, xres=None, yres=None):
self.xres = xres
self.yres = yres

def lower(self):
data = {
u"type": u"capture_image"
}
if self.xres:
data[u"xres"] = self.xres
if self.yres:
data[u"yres"] = self.yres
return data


class Delete:
Expand Down
2 changes: 1 addition & 1 deletion src/meshcat/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ def __init__(self, contents, mesh_format):

def lower(self, object_data):
return {
u"type": u"_meshfile",
u"type": u"_meshfile_geometry",
u"uuid": self.uuid,
u"format": self.mesh_format,
u"data": self.contents
Expand Down
3 changes: 3 additions & 0 deletions src/meshcat/servers/zmqserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,9 @@ def handle_zmq(self, frames):
self.zmq_socket.send(self.web_url.encode("utf-8"))
elif cmd == "wait":
self.ioloop.add_callback(self.wait_for_websockets)
elif cmd == "set_target":
self.forward_to_websockets(frames)
self.zmq_socket.send(b"ok")
elif cmd == "capture_image":
if len(self.websocket_pool) > 0:
self.forward_to_websockets(frames) # on_message callback should handle the pb
Expand Down
2 changes: 1 addition & 1 deletion src/meshcat/viewer
23 changes: 18 additions & 5 deletions src/meshcat/visualizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@


from .path import Path
from .commands import SetObject, SetTransform, Delete, SetProperty, SetAnimation, CaptureImage
from .commands import SetObject, SetTransform, Delete, SetProperty, SetAnimation, CaptureImage, SetCamTarget
from .geometry import MeshPhongMaterial
from .servers.zmqserver import start_zmq_server_as_subprocess

Expand Down Expand Up @@ -68,8 +68,8 @@ def get_scene(self):
# we receive the HTML as utf-8-encoded, so decode here
return self.zmq_socket.recv().decode('utf-8')

def get_image(self):
cmd_data = CaptureImage().lower()
def get_image(self, w, h):
cmd_data = CaptureImage(w, h).lower()
self.zmq_socket.send_multipart([
cmd_data["type"].encode("utf-8"),
"".encode("utf-8"),
Expand Down Expand Up @@ -157,9 +157,22 @@ def set_property(self, key, value):
def set_animation(self, animation, play=True, repetitions=1):
return self.window.send(SetAnimation(animation, play=play, repetitions=repetitions))

def get_image(self):
def set_cam_target(self, value):
"""Set camera target (in right-handed coordinates (x,y,z))."""
v = list(value)
v[1], v[2] = v[2], -v[1] # convert to left-handed (x,z,-y)
return self.window.send(SetCamTarget(v))

def set_cam_pos(self, value):
"""Set camera position (in right-handed coordinates (x,y,z))."""
path = "/Cameras/default/rotated/<object>"
v = list(value)
v[1], v[2] = v[2], -v[1] # convert to left-handed (x,z,-y)
return self[path].set_property("position", v)

def get_image(self, w=None, h=None):
"""Save an image"""
return self.window.get_image()
return self.window.get_image(w, h)

def delete(self):
return self.window.send(Delete(self.path))
Expand Down