From a374addc97d7439c2b076d57780ac3b224f3a1ed Mon Sep 17 00:00:00 2001 From: Shen Shen Date: Wed, 7 Nov 2018 12:58:33 -0500 Subject: [PATCH 01/12] Add 2D text. add text geometry (and PEP8 autofomat) add set_text() method and supporting logics split the texture from the rest of the object_json streamline material initialization demo WIP WIP add transparency parameter to differentiate scene and object texts fix transparent args and disentangle font size with face (for resizing) remove alphas finalizing --- demo.ipynb | 50 ++++++++++++++++ src/meshcat/commands.py | 46 ++++++++++++++- src/meshcat/geometry.py | 99 +++++++++++++++++++++++++++++--- src/meshcat/servers/zmqserver.py | 33 +++++++---- src/meshcat/visualizer.py | 13 +++-- 5 files changed, 216 insertions(+), 25 deletions(-) diff --git a/demo.ipynb b/demo.ipynb index dd3458a..9f464c5 100644 --- a/demo.ipynb +++ b/demo.ipynb @@ -153,6 +153,56 @@ "vis.delete()" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "MeshCat supports simple 2d texts rendering. For example, to write 2d texts onto a geometry or object:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "vis.set_text('Hello, world!',g.Box([1, 1, 1]),font_size=20)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It is also possible to simple write 'floating' texts onto a scene without attached to an object (e.g., for scene discription):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "vis.set_text('Hello, world!')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Under the hood, the 'floating' texts are written onto a `g.Plane()` geometry, so to change the texts size:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for i in np.linspace(10,2,20):\n", + " vis.set_text('Hello, world!', plane_width=2*i,plane_height=i,font_size=200)\n", + " time.sleep(0.05)" + ] + }, { "cell_type": "markdown", "metadata": {}, diff --git a/src/meshcat/commands.py b/src/meshcat/commands.py index 037bb5f..cebb693 100644 --- a/src/meshcat/commands.py +++ b/src/meshcat/commands.py @@ -4,14 +4,17 @@ if sys.version_info >= (3, 0): unicode = str -from .geometry import Geometry, Object, Mesh, MeshPhongMaterial, PointsMaterial, Points +from .geometry import (Geometry, Plane, Object, Mesh, +MeshPhongMaterial, PointsMaterial, Points, TextTexture) class SetObject: __slots__ = ["object", "path"] + def __init__(self, geometry_or_object, material=None, path=[]): if isinstance(geometry_or_object, Object): if material is not None: - raise(ArgumentError("Please supply either an Object OR a Geometry and a Material")) + raise(ArgumentError( + "Please supply either an Object OR a Geometry and a Material")) self.object = geometry_or_object else: if material is None: @@ -30,8 +33,46 @@ def lower(self): } +class SetText: + __slots__ = ["object", "path"] + + def __init__(self, text, geometry_or_object, plane_width=10, + plane_height=5, material=None, path=[], **kwargs): + self.text_texture = TextTexture(text, **kwargs) + if isinstance(geometry_or_object, Object): + if material is not None: + raise(ArgumentError( + "Please supply either an Object OR a Geometry and a Material")) + self.object = geometry_or_object + else: + if geometry_or_object is None: + geometry_or_object = Plane(width=plane_width, height=plane_height) + # if writing onto the scene, default material is transparent + material = MeshPhongMaterial(map=self.text_texture, + needsUpdate=True, transparent=True) + if material is None: + material = MeshPhongMaterial(map=self.text_texture, + needsUpdate=True) + if isinstance(material, PointsMaterial): + raise(ArgumentError( + "Cannot write text onto points; please supply a mesh material")) + else: + self.object = Mesh(geometry_or_object, material) + self.path = path + + def lower(self): + data = { + u"type": u"set_text", + u"object": self.object.lower(), + u"path": self.path.lower() + } + self.text_texture.lower_in_object(data) + return data + + class SetTransform: __slots__ = ["matrix", "path"] + def __init__(self, matrix, path=[]): self.matrix = matrix self.path = path @@ -46,6 +87,7 @@ def lower(self): class Delete: __slots__ = ["path"] + def __init__(self, path): self.path = path diff --git a/src/meshcat/geometry.py b/src/meshcat/geometry.py index 42c9d84..8a1914e 100644 --- a/src/meshcat/geometry.py +++ b/src/meshcat/geometry.py @@ -14,11 +14,13 @@ class SceneElement(object): + def __init__(self): self.uuid = unicode(uuid.uuid1()) class ReferenceSceneElement(SceneElement): + def lower_in_object(self, object_data): object_data.setdefault(self.field, []).append(self.lower(object_data)) return self.uuid @@ -44,6 +46,7 @@ class Image(ReferenceSceneElement): class Box(Geometry): + def __init__(self, lengths): super(Box, self).__init__() self.lengths = lengths @@ -59,6 +62,7 @@ def lower(self, object_data): class Sphere(Geometry): + def __init__(self, radius): super(Sphere, self).__init__() self.radius = radius @@ -68,8 +72,8 @@ def lower(self, object_data): u"uuid": self.uuid, u"type": u"SphereGeometry", u"radius": self.radius, - u"widthSegments" : 20, - u"heightSegments" : 20 + u"widthSegments": 20, + u"heightSegments": 20 } @@ -78,6 +82,7 @@ class Ellipsoid(Sphere): An Ellipsoid is treated as a Sphere of unit radius, with an affine transformation applied to distort it into the ellipsoidal shape """ + def __init__(self, radii): super(Ellipsoid, self).__init__(1.0) self.radii = radii @@ -86,11 +91,33 @@ def intrinsic_transform(self): return np.diag(np.hstack((self.radii, 1.0))) +class Plane(Geometry): + + def __init__(self, width=1, height=1, widthSegments=1, heightSegments=1): + super(Plane, self).__init__() + self.width = width + self.height = height + self.widthSegments = widthSegments + self.heightSegments = heightSegments + + def lower(self, object_data): + return { + u"uuid": self.uuid, + u"type": u"PlaneGeometry", + u"width": self.width, + u"height": self.height, + u"widthSegments": self.widthSegments, + u"heightSegments": self.heightSegments, + } + """ A cylinder of the given height and radius. By Three.js convention, the axis of rotational symmetry is aligned with the y-axis. """ + + class Cylinder(Geometry): + def __init__(self, height, radius=1.0, radiusTop=None, radiusBottom=None): super(Cylinder, self).__init__() if radiusTop is not None and radiusBottom is not None: @@ -114,11 +141,14 @@ def lower(self, object_data): class MeshMaterial(Material): - def __init__(self, color=0xffffff, reflectivity=0.5, map=None, **kwargs): + + def __init__(self, color=0xffffff, reflectivity=0.5, map=None, + transparent=False, **kwargs): super(MeshMaterial, self).__init__() self.color = color self.reflectivity = reflectivity self.map = map + self.transparent = transparent self.properties = kwargs def lower(self, object_data): @@ -127,6 +157,7 @@ def lower(self, object_data): u"type": self._type, u"color": self.color, u"reflectivity": self.reflectivity, + u"transparent": self.transparent } data.update(self.properties) if self.map is not None: @@ -135,22 +166,23 @@ def lower(self, object_data): class MeshBasicMaterial(MeshMaterial): - _type=u"MeshBasicMaterial" + _type = u"MeshBasicMaterial" class MeshPhongMaterial(MeshMaterial): - _type=u"MeshPhongMaterial" + _type = u"MeshPhongMaterial" class MeshLambertMaterial(MeshMaterial): - _type=u"MeshLambertMaterial" + _type = u"MeshLambertMaterial" class MeshToonMaterial(MeshMaterial): - _type=u"MeshToonMaterial" + _type = u"MeshToonMaterial" class PngImage(Image): + def __init__(self, data): super(PngImage, self).__init__() self.data = data @@ -167,7 +199,49 @@ def lower(self, object_data): } +class CanvasImage(Image): + + def __init__(self): + super(CanvasImage, self).__init__() + + def lower(self, object_data): + return { + u"uuid": self.uuid, + u"url": "" + } + + +class TextTexture(Texture): + + def __init__(self, text, font_size=96, font_face='sans-serif', + width=200, height=100, position=[10, 10]): + super(TextTexture, self).__init__() + self.text = text + # font_size will be passed to the JS side as is; however if the + # text width exceeds canvas width, font_size will be reduced. + self.font_size = font_size + self.font_face = font_face + self.width = width + self.height = height + self.position = position + self.image = CanvasImage() + + def lower(self, object_data): + return { + u"uuid": self.uuid, + u"type": u"TextTexture", + u"text": unicode(self.text), + u"font_size": self.font_size, + u"font_face": self.font_face, + u"width": self.width, + u"height": self.height, + u"position": self.position, + u"image": self.image.lower_in_object(object_data) + } + + class GenericTexture(Texture): + def __init__(self, properties): super(GenericTexture, self).__init__() self.properties = properties @@ -182,6 +256,7 @@ def lower(self, object_data): class ImageTexture(Texture): + def __init__(self, image, wrap=[1001, 1001], repeat=[1, 1], **kwargs): super(ImageTexture, self).__init__() self.image = image @@ -201,6 +276,7 @@ def lower(self, object_data): class GenericMaterial(Material): + def __init__(self, properties): self.properties = properties self.uuid = str(uuid.uuid1()) @@ -215,6 +291,7 @@ def lower(self, object_data): class Object(SceneElement): + def __init__(self, geometry, material=MeshPhongMaterial()): super(Object, self).__init__() self.geometry = geometry @@ -251,7 +328,8 @@ def item_size(array): elif array.ndim == 2: return array.shape[0] else: - raise ValueError("I can only pack 1- or 2-dimensional numpy arrays, but this one has {:d} dimensions".format(array.ndim)) + raise ValueError( + "I can only pack 1- or 2-dimensional numpy arrays, but this one has {:d} dimensions".format(array.ndim)) def threejs_type(dtype): @@ -280,6 +358,7 @@ def pack_numpy_array(x): class ObjMeshGeometry(Geometry): + def __init__(self, contents): super(ObjMeshGeometry, self).__init__() self.contents = contents @@ -299,6 +378,7 @@ def from_file(fname): class PointsGeometry(Geometry): + def __init__(self, position, color=None): super(PointsGeometry, self).__init__() self.position = position @@ -318,6 +398,7 @@ def lower(self, object_data): class PointsMaterial(Material): + def __init__(self, size=0.001, color=0xffffff): super(PointsMaterial, self).__init__() self.size = size @@ -336,6 +417,8 @@ def lower(self, object_data): class Points(Object): _type = u"Points" +class Texts(Object): + _type = u"_texttexture" def PointCloud(position, color, **kwargs): return Points( diff --git a/src/meshcat/servers/zmqserver.py b/src/meshcat/servers/zmqserver.py index 0c0004e..3ef5597 100644 --- a/src/meshcat/servers/zmqserver.py +++ b/src/meshcat/servers/zmqserver.py @@ -35,7 +35,8 @@ DEFAULT_ZMQ_METHOD = "tcp" DEFAULT_ZMQ_PORT = 6000 -MESHCAT_COMMANDS = ["set_transform", "set_object", "delete", "set_property", "set_animation"] +MESHCAT_COMMANDS = ["set_transform", "set_object", + "set_text", "delete", "set_property", "set_animation"] def find_available_port(func, default_port, max_attempts=MAX_ATTEMPTS): @@ -44,15 +45,18 @@ def find_available_port(func, default_port, max_attempts=MAX_ATTEMPTS): try: return func(port), port except (ADDRESS_IN_USE_ERROR, zmq.error.ZMQError): - print("Port: {:d} in use, trying another...".format(port), file=sys.stderr) + print("Port: {:d} in use, trying another...".format( + port), file=sys.stderr) except Exception as e: print(type(e)) raise else: - raise(Exception("Could not find an available port in the range: [{:d}, {:d})".format(default_port, max_attempts + default_port))) + raise(Exception("Could not find an available port in the range: [{:d}, {:d})".format( + default_port, max_attempts + default_port))) class WebSocketHandler(tornado.websocket.WebSocketHandler): + def __init__(self, *args, **kwargs): self.bridge = kwargs.pop("bridge") super(WebSocketHandler, self).__init__(*args, **kwargs) @@ -82,22 +86,27 @@ def __init__(self, zmq_url=None, host="127.0.0.1", port=None): if zmq_url is None: def f(port): return self.setup_zmq("{:s}://{:s}:{:d}".format(DEFAULT_ZMQ_METHOD, self.host, port)) - (self.zmq_socket, self.zmq_stream, self.zmq_url), _ = find_available_port(f, DEFAULT_ZMQ_PORT) + (self.zmq_socket, self.zmq_stream, + self.zmq_url), _ = find_available_port(f, DEFAULT_ZMQ_PORT) else: - self.zmq_socket, self.zmq_stream, self.zmq_url = self.setup_zmq(zmq_url) + self.zmq_socket, self.zmq_stream, self.zmq_url = self.setup_zmq( + zmq_url) if port is None: - _, self.fileserver_port = find_available_port(self.app.listen, DEFAULT_FILESERVER_PORT) + _, self.fileserver_port = find_available_port( + self.app.listen, DEFAULT_FILESERVER_PORT) else: self.app.listen(port) self.fileserver_port = port - self.web_url = "http://{host}:{port}/static/".format(host=self.host, port=self.fileserver_port) + self.web_url = "http://{host}:{port}/static/".format( + host=self.host, port=self.fileserver_port) self.tree = SceneTree() def make_app(self): return tornado.web.Application([ - (r"/static/(.*)", tornado.web.StaticFileHandler, {"path": VIEWER_ROOT, "default_filename": VIEWER_HTML}), + (r"/static/(.*)", tornado.web.StaticFileHandler, + {"path": VIEWER_ROOT, "default_filename": VIEWER_HTML}), (r"/", WebSocketHandler, {"bridge": self}) ]) @@ -117,13 +126,16 @@ def handle_zmq(self, frames): if len(frames) != 3: self.zmq_socket.send(b"error: expected 3 frames") return - path = list(filter(lambda x: len(x) > 0, frames[1].decode("utf-8").split("/"))) + path = list(filter(lambda x: len(x) > 0, frames[ + 1].decode("utf-8").split("/"))) data = frames[2] self.forward_to_websockets(frames) if cmd == "set_transform": find_node(self.tree, path).transform = data elif cmd == "set_object": find_node(self.tree, path).object = data + elif cmd == "set_text": + find_node(self.tree, path).object = data elif cmd == "delete": if len(path) > 0: parent = find_node(self.tree, path[:-1]) @@ -164,7 +176,8 @@ def main(): import sys import webbrowser - parser = argparse.ArgumentParser(description="Serve the MeshCat HTML files and listen for ZeroMQ commands") + parser = argparse.ArgumentParser( + description="Serve the MeshCat HTML files and listen for ZeroMQ commands") parser.add_argument('--zmq-url', '-z', type=str, nargs="?", default=None) parser.add_argument('--open', '-o', action="store_true") results = parser.parse_args() diff --git a/src/meshcat/visualizer.py b/src/meshcat/visualizer.py index bc223b7..98bf79d 100644 --- a/src/meshcat/visualizer.py +++ b/src/meshcat/visualizer.py @@ -10,7 +10,7 @@ import re from .path import Path -from .commands import SetObject, SetTransform, Delete, SetAnimation +from .commands import SetObject, SetText, SetTransform, Delete, SetAnimation from .geometry import MeshPhongMaterial @@ -21,9 +21,11 @@ def capture(pattern, s): else: return match.groups()[0] + def match_zmq_url(line): return capture(r"^zmq_url=(.*)$", line) + def match_web_url(line): return capture(r"^web_url=(.*)$", line) @@ -54,12 +56,9 @@ def __init__(self, zmq_url, start_server): # callback in the server until we reconnect. self.connect_zmq() - print("You can open the visualizer by visiting the following URL:") print(self.web_url) - - def connect_zmq(self): self.zmq_socket = self.context.socket(zmq.REQ) self.zmq_socket.connect(self.zmq_url) @@ -137,6 +136,11 @@ def set_object(self, geometry, material=None): def set_transform(self, matrix=np.eye(4)): return self.window.send(SetTransform(matrix, self.path)) + def set_text(self, text, geometry=None, plane_width=10, plane_height=5, + material=None,**kwargs): + return self.window.send(SetText(text, geometry, plane_width=plane_width, + plane_height=plane_height, material=material, path=self.path, **kwargs)) + def set_animation(self, animation, play=True, repetitions=1): return self.window.send(SetAnimation(animation, play=play, repetitions=repetitions)) @@ -163,4 +167,3 @@ def __repr__(self): while True: time.sleep(100) - From 378806f5a2c01fb38f7aea26169bd475f8d99dd0 Mon Sep 17 00:00:00 2001 From: Shen Shen Date: Fri, 15 Feb 2019 12:07:06 -0500 Subject: [PATCH 02/12] clean up --- src/meshcat/geometry.py | 29 +++++++---------------------- src/meshcat/visualizer.py | 6 ++++-- 2 files changed, 11 insertions(+), 24 deletions(-) diff --git a/src/meshcat/geometry.py b/src/meshcat/geometry.py index 8a1914e..44fbecc 100644 --- a/src/meshcat/geometry.py +++ b/src/meshcat/geometry.py @@ -14,13 +14,11 @@ class SceneElement(object): - def __init__(self): self.uuid = unicode(uuid.uuid1()) class ReferenceSceneElement(SceneElement): - def lower_in_object(self, object_data): object_data.setdefault(self.field, []).append(self.lower(object_data)) return self.uuid @@ -46,7 +44,6 @@ class Image(ReferenceSceneElement): class Box(Geometry): - def __init__(self, lengths): super(Box, self).__init__() self.lengths = lengths @@ -62,7 +59,6 @@ def lower(self, object_data): class Sphere(Geometry): - def __init__(self, radius): super(Sphere, self).__init__() self.radius = radius @@ -72,8 +68,8 @@ def lower(self, object_data): u"uuid": self.uuid, u"type": u"SphereGeometry", u"radius": self.radius, - u"widthSegments": 20, - u"heightSegments": 20 + u"widthSegments" : 20, + u"heightSegments" : 20 } @@ -82,7 +78,6 @@ class Ellipsoid(Sphere): An Ellipsoid is treated as a Sphere of unit radius, with an affine transformation applied to distort it into the ellipsoidal shape """ - def __init__(self, radii): super(Ellipsoid, self).__init__(1.0) self.radii = radii @@ -166,23 +161,22 @@ def lower(self, object_data): class MeshBasicMaterial(MeshMaterial): - _type = u"MeshBasicMaterial" + _type=u"MeshBasicMaterial" class MeshPhongMaterial(MeshMaterial): - _type = u"MeshPhongMaterial" + _type=u"MeshPhongMaterial" class MeshLambertMaterial(MeshMaterial): - _type = u"MeshLambertMaterial" + _type=u"MeshLambertMaterial" class MeshToonMaterial(MeshMaterial): - _type = u"MeshToonMaterial" + _type=u"MeshToonMaterial" class PngImage(Image): - def __init__(self, data): super(PngImage, self).__init__() self.data = data @@ -256,7 +250,6 @@ def lower(self, object_data): class ImageTexture(Texture): - def __init__(self, image, wrap=[1001, 1001], repeat=[1, 1], **kwargs): super(ImageTexture, self).__init__() self.image = image @@ -276,7 +269,6 @@ def lower(self, object_data): class GenericMaterial(Material): - def __init__(self, properties): self.properties = properties self.uuid = str(uuid.uuid1()) @@ -291,7 +283,6 @@ def lower(self, object_data): class Object(SceneElement): - def __init__(self, geometry, material=MeshPhongMaterial()): super(Object, self).__init__() self.geometry = geometry @@ -328,8 +319,7 @@ def item_size(array): elif array.ndim == 2: return array.shape[0] else: - raise ValueError( - "I can only pack 1- or 2-dimensional numpy arrays, but this one has {:d} dimensions".format(array.ndim)) + raise ValueError("I can only pack 1- or 2-dimensional numpy arrays, but this one has {:d} dimensions".format(array.ndim)) def threejs_type(dtype): @@ -358,7 +348,6 @@ def pack_numpy_array(x): class ObjMeshGeometry(Geometry): - def __init__(self, contents): super(ObjMeshGeometry, self).__init__() self.contents = contents @@ -378,7 +367,6 @@ def from_file(fname): class PointsGeometry(Geometry): - def __init__(self, position, color=None): super(PointsGeometry, self).__init__() self.position = position @@ -398,7 +386,6 @@ def lower(self, object_data): class PointsMaterial(Material): - def __init__(self, size=0.001, color=0xffffff): super(PointsMaterial, self).__init__() self.size = size @@ -417,8 +404,6 @@ def lower(self, object_data): class Points(Object): _type = u"Points" -class Texts(Object): - _type = u"_texttexture" def PointCloud(position, color, **kwargs): return Points( diff --git a/src/meshcat/visualizer.py b/src/meshcat/visualizer.py index 98bf79d..ad9fa76 100644 --- a/src/meshcat/visualizer.py +++ b/src/meshcat/visualizer.py @@ -21,11 +21,9 @@ def capture(pattern, s): else: return match.groups()[0] - def match_zmq_url(line): return capture(r"^zmq_url=(.*)$", line) - def match_web_url(line): return capture(r"^web_url=(.*)$", line) @@ -56,9 +54,12 @@ def __init__(self, zmq_url, start_server): # callback in the server until we reconnect. self.connect_zmq() + print("You can open the visualizer by visiting the following URL:") print(self.web_url) + + def connect_zmq(self): self.zmq_socket = self.context.socket(zmq.REQ) self.zmq_socket.connect(self.zmq_url) @@ -167,3 +168,4 @@ def __repr__(self): while True: time.sleep(100) + From ffb52336178b0acb157308b25d81aee23ffcf5e7 Mon Sep 17 00:00:00 2001 From: Shen Shen Date: Fri, 15 Feb 2019 12:55:00 -0500 Subject: [PATCH 03/12] update demo --- demo.ipynb | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/demo.ipynb b/demo.ipynb index 9f464c5..66e3013 100644 --- a/demo.ipynb +++ b/demo.ipynb @@ -166,14 +166,14 @@ "metadata": {}, "outputs": [], "source": [ - "vis.set_text('Hello, world!',g.Box([1, 1, 1]),font_size=20)" + "vis.set_text('Hello, world!',g.Box([1, 1, 2]),font_size=20)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "It is also possible to simple write 'floating' texts onto a scene without attached to an object (e.g., for scene discription):" + "It is also possible to simple write 'floating' texts onto a scene without attached to an object (e.g., for scene description):" ] }, { @@ -182,6 +182,7 @@ "metadata": {}, "outputs": [], "source": [ + "vis.delete()\n", "vis.set_text('Hello, world!')" ] }, @@ -189,7 +190,25 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Under the hood, the 'floating' texts are written onto a `g.Plane()` geometry, so to change the texts size:" + "and just like the usual geometry/object, the texts can be rotated:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "Rz = tf.rotation_matrix(np.pi/2, [0, 0, 1])\n", + "Ry = tf.rotation_matrix(np.pi/2, [0, 1, 0])\n", + "vis.set_transform(Ry.dot(Rz))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Under the hood, the 'floating' texts are written onto a `Plane()` geometry, and the plane size can be specified with plane_width and plane_height. These two parameters affect the texts size when the font_size itself is set too large; they would force a font resizing when rendering so as to fit all the texts within the specified plane." ] }, { @@ -199,7 +218,7 @@ "outputs": [], "source": [ "for i in np.linspace(10,2,20):\n", - " vis.set_text('Hello, world!', plane_width=2*i,plane_height=i,font_size=200)\n", + " vis.set_text('Hello, world!', plane_width=2*i, plane_height=i, font_size=200)\n", " time.sleep(0.05)" ] }, From 3b33b39d8735e1f03601b95bfa93b5fc290a60a5 Mon Sep 17 00:00:00 2001 From: Shen Shen Date: Fri, 15 Feb 2019 13:35:46 -0500 Subject: [PATCH 04/12] clean up --- src/meshcat/geometry.py | 5 +---- src/meshcat/servers/zmqserver.py | 28 +++++++++------------------- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/src/meshcat/geometry.py b/src/meshcat/geometry.py index ee6a4dd..f6577a7 100644 --- a/src/meshcat/geometry.py +++ b/src/meshcat/geometry.py @@ -109,8 +109,6 @@ def lower(self, object_data): A cylinder of the given height and radius. By Three.js convention, the axis of rotational symmetry is aligned with the y-axis. """ - - class Cylinder(Geometry): def __init__(self, height, radius=1.0, radiusTop=None, radiusBottom=None): @@ -137,7 +135,7 @@ def lower(self, object_data): class MeshMaterial(Material): - def __init__(self, color=0xffffff, reflectivity=0.5, map=None, + def __init__(self, color=0xffffff, reflectivity=0.5, map=None,side=2, transparent=False, **kwargs): super(MeshMaterial, self).__init__() self.color = color @@ -237,7 +235,6 @@ def lower(self, object_data): class GenericTexture(Texture): - def __init__(self, properties): super(GenericTexture, self).__init__() self.properties = properties diff --git a/src/meshcat/servers/zmqserver.py b/src/meshcat/servers/zmqserver.py index 3ef5597..c8bb3df 100644 --- a/src/meshcat/servers/zmqserver.py +++ b/src/meshcat/servers/zmqserver.py @@ -45,18 +45,15 @@ def find_available_port(func, default_port, max_attempts=MAX_ATTEMPTS): try: return func(port), port except (ADDRESS_IN_USE_ERROR, zmq.error.ZMQError): - print("Port: {:d} in use, trying another...".format( - port), file=sys.stderr) + print("Port: {:d} in use, trying another...".format(port), file=sys.stderr) except Exception as e: print(type(e)) raise else: - raise(Exception("Could not find an available port in the range: [{:d}, {:d})".format( - default_port, max_attempts + default_port))) + raise(Exception("Could not find an available port in the range: [{:d}, {:d})".format(default_port, max_attempts + default_port))) class WebSocketHandler(tornado.websocket.WebSocketHandler): - def __init__(self, *args, **kwargs): self.bridge = kwargs.pop("bridge") super(WebSocketHandler, self).__init__(*args, **kwargs) @@ -86,27 +83,22 @@ def __init__(self, zmq_url=None, host="127.0.0.1", port=None): if zmq_url is None: def f(port): return self.setup_zmq("{:s}://{:s}:{:d}".format(DEFAULT_ZMQ_METHOD, self.host, port)) - (self.zmq_socket, self.zmq_stream, - self.zmq_url), _ = find_available_port(f, DEFAULT_ZMQ_PORT) + (self.zmq_socket, self.zmq_stream, self.zmq_url), _ = find_available_port(f, DEFAULT_ZMQ_PORT) else: - self.zmq_socket, self.zmq_stream, self.zmq_url = self.setup_zmq( - zmq_url) + self.zmq_socket, self.zmq_stream, self.zmq_url = self.setup_zmq(zmq_url) if port is None: - _, self.fileserver_port = find_available_port( - self.app.listen, DEFAULT_FILESERVER_PORT) + _, self.fileserver_port = find_available_port(self.app.listen, DEFAULT_FILESERVER_PORT) else: self.app.listen(port) self.fileserver_port = port - self.web_url = "http://{host}:{port}/static/".format( - host=self.host, port=self.fileserver_port) + self.web_url = "http://{host}:{port}/static/".format(host=self.host, port=self.fileserver_port) self.tree = SceneTree() def make_app(self): return tornado.web.Application([ - (r"/static/(.*)", tornado.web.StaticFileHandler, - {"path": VIEWER_ROOT, "default_filename": VIEWER_HTML}), + (r"/static/(.*)", tornado.web.StaticFileHandler,{"path": VIEWER_ROOT, "default_filename": VIEWER_HTML}), (r"/", WebSocketHandler, {"bridge": self}) ]) @@ -126,8 +118,7 @@ def handle_zmq(self, frames): if len(frames) != 3: self.zmq_socket.send(b"error: expected 3 frames") return - path = list(filter(lambda x: len(x) > 0, frames[ - 1].decode("utf-8").split("/"))) + path = list(filter(lambda x: len(x) > 0, frames[1].decode("utf-8").split("/"))) data = frames[2] self.forward_to_websockets(frames) if cmd == "set_transform": @@ -176,8 +167,7 @@ def main(): import sys import webbrowser - parser = argparse.ArgumentParser( - description="Serve the MeshCat HTML files and listen for ZeroMQ commands") + parser = argparse.ArgumentParser(description="Serve the MeshCat HTML files and listen for ZeroMQ commands") parser.add_argument('--zmq-url', '-z', type=str, nargs="?", default=None) parser.add_argument('--open', '-o', action="store_true") results = parser.parse_args() From ae852a3bf5f75524942dfbf1e90c949f688c1900 Mon Sep 17 00:00:00 2001 From: Shen Shen Date: Fri, 15 Feb 2019 13:40:32 -0500 Subject: [PATCH 05/12] clean up --- src/meshcat/geometry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/meshcat/geometry.py b/src/meshcat/geometry.py index f6577a7..cefe9ed 100644 --- a/src/meshcat/geometry.py +++ b/src/meshcat/geometry.py @@ -151,7 +151,7 @@ def lower(self, object_data): u"type": self._type, u"color": self.color, u"reflectivity": self.reflectivity, - u"transparent": self.transparent + u"transparent": self.transparent, u"side": self.side } data.update(self.properties) From acd66943d4bc98ad7d24cff1e0afd9699332237a Mon Sep 17 00:00:00 2001 From: Shen Shen Date: Fri, 15 Feb 2019 13:52:50 -0500 Subject: [PATCH 06/12] clean up --- demo.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo.ipynb b/demo.ipynb index 66e3013..71242d7 100644 --- a/demo.ipynb +++ b/demo.ipynb @@ -217,7 +217,7 @@ "metadata": {}, "outputs": [], "source": [ - "for i in np.linspace(10,2,20):\n", + "for i in np.linspace(8,2,10):\n", " vis.set_text('Hello, world!', plane_width=2*i, plane_height=i, font_size=200)\n", " time.sleep(0.05)" ] From 4677e2ecd201e09951f10d53a81e4ce40d8d5308 Mon Sep 17 00:00:00 2001 From: Shen Shen Date: Fri, 1 Mar 2019 07:36:00 -0500 Subject: [PATCH 07/12] replace set_text with set_object logics --- demo.ipynb | 8 ++--- src/meshcat/commands.py | 42 +++----------------------- src/meshcat/geometry.py | 52 ++++++++++++++++++++------------ src/meshcat/servers/zmqserver.py | 6 ++-- src/meshcat/visualizer.py | 10 ++---- 5 files changed, 45 insertions(+), 73 deletions(-) diff --git a/demo.ipynb b/demo.ipynb index 71242d7..26874fa 100644 --- a/demo.ipynb +++ b/demo.ipynb @@ -166,7 +166,7 @@ "metadata": {}, "outputs": [], "source": [ - "vis.set_text('Hello, world!',g.Box([1, 1, 2]),font_size=20)" + "vis.set_object(g.Box([1, 1, 2]),texts='Hello, world!')" ] }, { @@ -183,7 +183,7 @@ "outputs": [], "source": [ "vis.delete()\n", - "vis.set_text('Hello, world!')" + "vis.set_object(g.SceneText('Hello, world!',font_size=100))" ] }, { @@ -208,7 +208,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Under the hood, the 'floating' texts are written onto a `Plane()` geometry, and the plane size can be specified with plane_width and plane_height. These two parameters affect the texts size when the font_size itself is set too large; they would force a font resizing when rendering so as to fit all the texts within the specified plane." + "Under the hood, the SceneTexts are written onto a `Plane()` geometry, and the plane size can be specified with width and height. These two parameters affect the texts size when the font_size itself is set too large; they would force a font resizing when rendering so as to fit all the texts within the specified plane." ] }, { @@ -218,7 +218,7 @@ "outputs": [], "source": [ "for i in np.linspace(8,2,10):\n", - " vis.set_text('Hello, world!', plane_width=2*i, plane_height=i, font_size=200)\n", + " vis.set_object(g.SceneText('Hello, world!',width=2*i,height=2*i,font_size=300))\n", " time.sleep(0.05)" ] }, diff --git a/src/meshcat/commands.py b/src/meshcat/commands.py index cebb693..9b89824 100644 --- a/src/meshcat/commands.py +++ b/src/meshcat/commands.py @@ -10,7 +10,7 @@ class SetObject: __slots__ = ["object", "path"] - def __init__(self, geometry_or_object, material=None, path=[]): + def __init__(self, geometry_or_object, material=None, texts=None, path=[]): if isinstance(geometry_or_object, Object): if material is not None: raise(ArgumentError( @@ -22,6 +22,9 @@ def __init__(self, geometry_or_object, material=None, path=[]): if isinstance(material, PointsMaterial): self.object = Points(geometry_or_object, material) else: + if texts is not None: + material.map = TextTexture(texts) + material.needsUpdate = True self.object = Mesh(geometry_or_object, material) self.path = path @@ -33,43 +36,6 @@ def lower(self): } -class SetText: - __slots__ = ["object", "path"] - - def __init__(self, text, geometry_or_object, plane_width=10, - plane_height=5, material=None, path=[], **kwargs): - self.text_texture = TextTexture(text, **kwargs) - if isinstance(geometry_or_object, Object): - if material is not None: - raise(ArgumentError( - "Please supply either an Object OR a Geometry and a Material")) - self.object = geometry_or_object - else: - if geometry_or_object is None: - geometry_or_object = Plane(width=plane_width, height=plane_height) - # if writing onto the scene, default material is transparent - material = MeshPhongMaterial(map=self.text_texture, - needsUpdate=True, transparent=True) - if material is None: - material = MeshPhongMaterial(map=self.text_texture, - needsUpdate=True) - if isinstance(material, PointsMaterial): - raise(ArgumentError( - "Cannot write text onto points; please supply a mesh material")) - else: - self.object = Mesh(geometry_or_object, material) - self.path = path - - def lower(self): - data = { - u"type": u"set_text", - u"object": self.object.lower(), - u"path": self.path.lower() - } - self.text_texture.lower_in_object(data) - return data - - class SetTransform: __slots__ = ["matrix", "path"] diff --git a/src/meshcat/geometry.py b/src/meshcat/geometry.py index cefe9ed..330c15c 100644 --- a/src/meshcat/geometry.py +++ b/src/meshcat/geometry.py @@ -193,47 +193,46 @@ def lower(self, object_data): } -class CanvasImage(Image): +# class CanvasImage(Image): - def __init__(self): - super(CanvasImage, self).__init__() +# def __init__(self): +# super(CanvasImage, self).__init__() - def lower(self, object_data): - return { - u"uuid": self.uuid, - u"url": "" - } +# def lower(self, object_data): +# return { +# u"uuid": self.uuid, +# u"url": "" +# } class TextTexture(Texture): - def __init__(self, text, font_size=96, font_face='sans-serif', + def __init__(self, text, font_size=100, font_face='sans-serif', width=200, height=100, position=[10, 10]): super(TextTexture, self).__init__() self.text = text - # font_size will be passed to the JS side as is; however if the + # font_size will be passed to the JS side as is; however if the # text width exceeds canvas width, font_size will be reduced. self.font_size = font_size self.font_face = font_face - self.width = width - self.height = height - self.position = position - self.image = CanvasImage() + # self.width = width + # self.height = height + # self.position = position + # self.image = CanvasImage() def lower(self, object_data): return { u"uuid": self.uuid, - u"type": u"TextTexture", + u"type": u"_text", u"text": unicode(self.text), u"font_size": self.font_size, u"font_face": self.font_face, - u"width": self.width, - u"height": self.height, - u"position": self.position, - u"image": self.image.lower_in_object(object_data) + # u"width": self.width, + # u"height": self.height, + # u"position": self.position, + # u"image": self.image.lower_in_object(object_data) } - class GenericTexture(Texture): def __init__(self, properties): super(GenericTexture, self).__init__() @@ -409,3 +408,16 @@ def PointCloud(position, color, **kwargs): PointsGeometry(position, color), PointsMaterial(**kwargs) ) + + +def SceneText(text, **kwargs): + if 'width' in kwargs and 'height' in kwargs: + plane = Plane(kwargs.pop('width'), kwargs.pop('height')) + else: + plane = Plane(width=10,height=10) + return Mesh( + plane, + MeshPhongMaterial(map=TextTexture(text,**kwargs),transparent=True, + needsUpdate=True) + ) + diff --git a/src/meshcat/servers/zmqserver.py b/src/meshcat/servers/zmqserver.py index c8bb3df..bfc0a6f 100644 --- a/src/meshcat/servers/zmqserver.py +++ b/src/meshcat/servers/zmqserver.py @@ -35,8 +35,8 @@ DEFAULT_ZMQ_METHOD = "tcp" DEFAULT_ZMQ_PORT = 6000 -MESHCAT_COMMANDS = ["set_transform", "set_object", - "set_text", "delete", "set_property", "set_animation"] +MESHCAT_COMMANDS = ["set_transform", "set_object", "delete", "set_property", +"set_animation"] def find_available_port(func, default_port, max_attempts=MAX_ATTEMPTS): @@ -125,8 +125,6 @@ def handle_zmq(self, frames): find_node(self.tree, path).transform = data elif cmd == "set_object": find_node(self.tree, path).object = data - elif cmd == "set_text": - find_node(self.tree, path).object = data elif cmd == "delete": if len(path) > 0: parent = find_node(self.tree, path[:-1]) diff --git a/src/meshcat/visualizer.py b/src/meshcat/visualizer.py index 597eda4..699edec 100644 --- a/src/meshcat/visualizer.py +++ b/src/meshcat/visualizer.py @@ -134,17 +134,13 @@ def jupyter_cell(self): def __getitem__(self, path): return Visualizer.view_into(self.window, self.path.append(path)) - def set_object(self, geometry, material=None): - return self.window.send(SetObject(geometry, material, self.path)) + def set_object(self, geometry, material=None, texts=None): + return self.window.send(SetObject(geometry, material, texts, + self.path)) def set_transform(self, matrix=np.eye(4)): return self.window.send(SetTransform(matrix, self.path)) - def set_text(self, text, geometry=None, plane_width=10, plane_height=5, - material=None,**kwargs): - return self.window.send(SetText(text, geometry, plane_width=plane_width, - plane_height=plane_height, material=material, path=self.path, **kwargs)) - def set_animation(self, animation, play=True, repetitions=1): return self.window.send(SetAnimation(animation, play=play, repetitions=repetitions)) From bee1a230e0a1cb9995bcc6b1aabab48fdbbb84f4 Mon Sep 17 00:00:00 2001 From: Shen Shen Date: Fri, 1 Mar 2019 07:42:10 -0500 Subject: [PATCH 08/12] clean up --- src/meshcat/commands.py | 3 --- src/meshcat/geometry.py | 20 -------------------- src/meshcat/servers/zmqserver.py | 5 ++--- src/meshcat/visualizer.py | 2 +- 4 files changed, 3 insertions(+), 27 deletions(-) diff --git a/src/meshcat/commands.py b/src/meshcat/commands.py index 9b89824..4c3ec6a 100644 --- a/src/meshcat/commands.py +++ b/src/meshcat/commands.py @@ -9,7 +9,6 @@ class SetObject: __slots__ = ["object", "path"] - def __init__(self, geometry_or_object, material=None, texts=None, path=[]): if isinstance(geometry_or_object, Object): if material is not None: @@ -38,7 +37,6 @@ def lower(self): class SetTransform: __slots__ = ["matrix", "path"] - def __init__(self, matrix, path=[]): self.matrix = matrix self.path = path @@ -53,7 +51,6 @@ def lower(self): class Delete: __slots__ = ["path"] - def __init__(self, path): self.path = path diff --git a/src/meshcat/geometry.py b/src/meshcat/geometry.py index aa2e188..50d0dda 100644 --- a/src/meshcat/geometry.py +++ b/src/meshcat/geometry.py @@ -205,18 +205,6 @@ def lower(self, object_data): } -# class CanvasImage(Image): - -# def __init__(self): -# super(CanvasImage, self).__init__() - -# def lower(self, object_data): -# return { -# u"uuid": self.uuid, -# u"url": "" -# } - - class TextTexture(Texture): def __init__(self, text, font_size=100, font_face='sans-serif', @@ -227,10 +215,6 @@ def __init__(self, text, font_size=100, font_face='sans-serif', # text width exceeds canvas width, font_size will be reduced. self.font_size = font_size self.font_face = font_face - # self.width = width - # self.height = height - # self.position = position - # self.image = CanvasImage() def lower(self, object_data): return { @@ -239,10 +223,6 @@ def lower(self, object_data): u"text": unicode(self.text), u"font_size": self.font_size, u"font_face": self.font_face, - # u"width": self.width, - # u"height": self.height, - # u"position": self.position, - # u"image": self.image.lower_in_object(object_data) } class GenericTexture(Texture): diff --git a/src/meshcat/servers/zmqserver.py b/src/meshcat/servers/zmqserver.py index bfc0a6f..0c0004e 100644 --- a/src/meshcat/servers/zmqserver.py +++ b/src/meshcat/servers/zmqserver.py @@ -35,8 +35,7 @@ DEFAULT_ZMQ_METHOD = "tcp" DEFAULT_ZMQ_PORT = 6000 -MESHCAT_COMMANDS = ["set_transform", "set_object", "delete", "set_property", -"set_animation"] +MESHCAT_COMMANDS = ["set_transform", "set_object", "delete", "set_property", "set_animation"] def find_available_port(func, default_port, max_attempts=MAX_ATTEMPTS): @@ -98,7 +97,7 @@ def f(port): def make_app(self): return tornado.web.Application([ - (r"/static/(.*)", tornado.web.StaticFileHandler,{"path": VIEWER_ROOT, "default_filename": VIEWER_HTML}), + (r"/static/(.*)", tornado.web.StaticFileHandler, {"path": VIEWER_ROOT, "default_filename": VIEWER_HTML}), (r"/", WebSocketHandler, {"bridge": self}) ]) diff --git a/src/meshcat/visualizer.py b/src/meshcat/visualizer.py index 699edec..1cb025c 100644 --- a/src/meshcat/visualizer.py +++ b/src/meshcat/visualizer.py @@ -11,7 +11,7 @@ import re from .path import Path -from .commands import SetObject, SetText, SetTransform, Delete, SetAnimation +from .commands import SetObject, SetTransform, Delete, SetAnimation from .geometry import MeshPhongMaterial From ae90a3a6ae64a1f3ec9a87b9a75d53c78638c3a9 Mon Sep 17 00:00:00 2001 From: Shen Shen Date: Fri, 1 Mar 2019 07:45:03 -0500 Subject: [PATCH 09/12] revert transparent handling --- src/meshcat/geometry.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/meshcat/geometry.py b/src/meshcat/geometry.py index 50d0dda..881b739 100644 --- a/src/meshcat/geometry.py +++ b/src/meshcat/geometry.py @@ -140,7 +140,6 @@ def __init__(self, color=0xffffff, reflectivity=0.5, map=None, self.color = color self.reflectivity = reflectivity self.map = map - self.transparent = transparent self.properties = kwargs self.side = side self.transparent = transparent @@ -163,7 +162,7 @@ def lower(self, object_data): u"color": self.color, u"reflectivity": self.reflectivity, u"side": self.side, - u"transparent": self.transparent, + u"transparent": transparent, u"opacity": self.opacity } data.update(self.properties) From 7474b562441e962a2ed8f1aa76560f078c98cf34 Mon Sep 17 00:00:00 2001 From: Shen Shen Date: Fri, 1 Mar 2019 08:24:03 -0500 Subject: [PATCH 10/12] revert auto-formatting changes --- src/meshcat/commands.py | 3 +-- src/meshcat/geometry.py | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/meshcat/commands.py b/src/meshcat/commands.py index 4c3ec6a..534f8c5 100644 --- a/src/meshcat/commands.py +++ b/src/meshcat/commands.py @@ -12,8 +12,7 @@ class SetObject: def __init__(self, geometry_or_object, material=None, texts=None, path=[]): if isinstance(geometry_or_object, Object): if material is not None: - raise(ArgumentError( - "Please supply either an Object OR a Geometry and a Material")) + raise(ArgumentError("Please supply either an Object OR a Geometry and a Material")) self.object = geometry_or_object else: if material is None: diff --git a/src/meshcat/geometry.py b/src/meshcat/geometry.py index 881b739..d717023 100644 --- a/src/meshcat/geometry.py +++ b/src/meshcat/geometry.py @@ -110,7 +110,6 @@ def lower(self, object_data): rotational symmetry is aligned with the y-axis. """ class Cylinder(Geometry): - def __init__(self, height, radius=1.0, radiusTop=None, radiusBottom=None): super(Cylinder, self).__init__() if radiusTop is not None and radiusBottom is not None: From 940acbce6103080dcd518e91d98acac065beebd2 Mon Sep 17 00:00:00 2001 From: Shen Shen Date: Sun, 3 Mar 2019 17:35:07 -0500 Subject: [PATCH 11/12] address Robin's comments --- demo.ipynb | 10 +++++----- src/meshcat/commands.py | 5 +---- src/meshcat/geometry.py | 7 ++----- src/meshcat/visualizer.py | 5 ++--- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/demo.ipynb b/demo.ipynb index 456fcd5..5562863 100644 --- a/demo.ipynb +++ b/demo.ipynb @@ -157,7 +157,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "MeshCat supports simple 2d texts rendering. For example, to write 2d texts onto a geometry or object:" + "MeshCat supports simple 2d texts rendering. For example, to write 2d texts onto a geometry:" ] }, { @@ -166,14 +166,14 @@ "metadata": {}, "outputs": [], "source": [ - "vis.set_object(g.Box([1, 1, 2]),texts='Hello, world!')" + "vis.set_object(g.Box([1, 1, 2]),g.MeshPhongMaterial(map=g.TextTexture('Hello, world!')))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "It is also possible to simple write 'floating' texts onto a scene without attached to an object (e.g., for scene description):" + "It is also possible to simple write 'floating' texts onto a scene without attaching it to an object (e.g., for scene description):" ] }, { @@ -190,7 +190,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "and just like the usual geometry/object, the texts can be rotated:" + "and just like the usual geometry/object, the scene texts can be rotated:" ] }, { @@ -208,7 +208,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Under the hood, the SceneTexts are written onto a `Plane()` geometry, and the plane size can be specified with width and height. These two parameters affect the texts size when the font_size itself is set too large; they would force a font resizing when rendering so as to fit all the texts within the specified plane." + "Under the hood, the `SceneTexts` are written onto a `Plane` geometry, and the plane size can be specified by width and height. These two parameters affect the texts size when the font_size itself is set too large; they would force a font downsizing when rendering so as to fit all the texts within the specified plane." ] }, { diff --git a/src/meshcat/commands.py b/src/meshcat/commands.py index 534f8c5..ad30ea7 100644 --- a/src/meshcat/commands.py +++ b/src/meshcat/commands.py @@ -9,7 +9,7 @@ class SetObject: __slots__ = ["object", "path"] - def __init__(self, geometry_or_object, material=None, texts=None, path=[]): + def __init__(self, geometry_or_object, material=None, path=[]): if isinstance(geometry_or_object, Object): if material is not None: raise(ArgumentError("Please supply either an Object OR a Geometry and a Material")) @@ -20,9 +20,6 @@ def __init__(self, geometry_or_object, material=None, texts=None, path=[]): if isinstance(material, PointsMaterial): self.object = Points(geometry_or_object, material) else: - if texts is not None: - material.map = TextTexture(texts) - material.needsUpdate = True self.object = Mesh(geometry_or_object, material) self.path = path diff --git a/src/meshcat/geometry.py b/src/meshcat/geometry.py index d717023..24cfda1 100644 --- a/src/meshcat/geometry.py +++ b/src/meshcat/geometry.py @@ -429,11 +429,8 @@ def PointCloud(position, color, **kwargs): ) -def SceneText(text, **kwargs): - if 'width' in kwargs and 'height' in kwargs: - plane = Plane(kwargs.pop('width'), kwargs.pop('height')) - else: - plane = Plane(width=10,height=10) +def SceneText(text, width=10, height=10, **kwargs): + plane = Plane(width=width,height=height) return Mesh( plane, MeshPhongMaterial(map=TextTexture(text,**kwargs),transparent=True, diff --git a/src/meshcat/visualizer.py b/src/meshcat/visualizer.py index 1cb025c..b73d9c8 100644 --- a/src/meshcat/visualizer.py +++ b/src/meshcat/visualizer.py @@ -134,9 +134,8 @@ def jupyter_cell(self): def __getitem__(self, path): return Visualizer.view_into(self.window, self.path.append(path)) - def set_object(self, geometry, material=None, texts=None): - return self.window.send(SetObject(geometry, material, texts, - self.path)) + def set_object(self, geometry, material=None): + return self.window.send(SetObject(geometry, material, self.path)) def set_transform(self, matrix=np.eye(4)): return self.window.send(SetTransform(matrix, self.path)) From 9932bb9f67550a6df16f73458f19a4325e14164a Mon Sep 17 00:00:00 2001 From: Shen Shen Date: Sun, 3 Mar 2019 17:48:57 -0500 Subject: [PATCH 12/12] clean up --- src/meshcat/geometry.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/meshcat/geometry.py b/src/meshcat/geometry.py index 82ad6b1..8938658 100644 --- a/src/meshcat/geometry.py +++ b/src/meshcat/geometry.py @@ -431,9 +431,8 @@ def PointCloud(position, color, **kwargs): def SceneText(text, width=10, height=10, **kwargs): - plane = Plane(width=width,height=height) return Mesh( - plane, + Plane(width=width,height=height), MeshPhongMaterial(map=TextTexture(text,**kwargs),transparent=True, needsUpdate=True) ) @@ -449,4 +448,3 @@ class LineSegments(Object): class LineLoop(Object): _type = u"LineLoop" -