Skip to content

[rebased] Text rendering: python-side #111

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 25, 2022
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
69 changes: 69 additions & 0 deletions examples/demo.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,75 @@
"vis.delete()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"MeshCat supports simple 2d texts rendering. For example, to write 2d texts onto a geometry:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"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 attaching it to an object (e.g., for scene description):"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"vis.delete()\n",
"vis.set_object(g.SceneText('Hello, world!',font_size=100))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"and just like the usual geometry/object, the scene 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 `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."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"for i in np.linspace(8,2,10):\n",
" vis.set_object(g.SceneText('Hello, world!',width=2*i,height=2*i,font_size=300))\n",
" time.sleep(0.05)"
]
},
{
"cell_type": "markdown",
"metadata": {},
Expand Down
2 changes: 1 addition & 1 deletion src/meshcat/commands.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .geometry import Geometry, Object, Mesh, MeshPhongMaterial, OrthographicCamera, PerspectiveCamera, PointsMaterial, Points
from .geometry import Geometry, Object, Mesh, MeshPhongMaterial, OrthographicCamera, PerspectiveCamera, PointsMaterial, Points, TextTexture
from .path import Path


Expand Down
46 changes: 46 additions & 0 deletions src/meshcat/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,26 @@ 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.
Expand Down Expand Up @@ -195,6 +215,25 @@ def lower(self, object_data):
}


class TextTexture(Texture):
def __init__(self, text, font_size=100, font_face='sans-serif'):
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

def lower(self, object_data):
return {
u"uuid": self.uuid,
u"type": u"_text",
u"text": self.text,
u"font_size": self.font_size,
u"font_face": self.font_face,
}


class GenericTexture(Texture):
def __init__(self, properties):
super(GenericTexture, self).__init__()
Expand Down Expand Up @@ -551,6 +590,13 @@ def PointCloud(position, color, **kwargs):
)


def SceneText(text, width=10, height=10, **kwargs):
return Mesh(
Plane(width=width,height=height),
MeshPhongMaterial(map=TextTexture(text,**kwargs),transparent=True,
needsUpdate=True)
)

class Line(Object):
_type = u"Line"

Expand Down