Source code for ladybug_rhino.text
"""Functions to add text to the Rhino scene and create Grasshopper text objects."""
from __future__ import division
import math
from .fromgeometry import from_plane
from .color import black
try:
import System.Guid as guid
except ImportError as e:
print("Failed to import System\n{}".format(e))
try:
import Rhino as rh
except ImportError as e:
raise ImportError("Failed to import Rhino.\n{}".format(e))
try:
import Grasshopper as gh
except ImportError:
pass
[docs]
def text_objects(text, plane, height, font='Arial',
horizontal_alignment=0, vertical_alignment=5):
"""Generate a Bake-able Grasshopper text object from a text string and ladybug Plane.
Args:
text: A text string to be converted to a a Grasshopper text object.
plane: A Ladybug Plane object to locate and orient the text in the Rhino scene.
height: A number for the height of the text in the Rhino scene.
font: An optional text string for the font in which to draw the text.
horizontal_alignment: An optional integer to specify the horizontal alignment
of the text. Choose from: (0 = Left, 1 = Center, 2 = Right)
vertical_alignment: An optional integer to specify the vertical alignment
of the text. Choose from: (0 = Top, 1 = MiddleOfTop, 2 = BottomOfTop,
3 = Middle, 4 = MiddleOfBottom, 5 = Bottom, 6 = BottomOfBoundingBox)
"""
txt = rh.Display.Text3d(text, from_plane(plane), height)
txt.FontFace = font
txt.HorizontalAlignment = AlignmentTypes.horizontal(horizontal_alignment)
txt.VerticalAlignment = AlignmentTypes.vertical(vertical_alignment)
return TextGoo(txt)
"""____________EXTRA HELPER OBJECTS____________"""
[docs]
class TextGoo(gh.Kernel.Types.GH_GeometricGoo[rh.Display.Text3d],
gh.Kernel.IGH_BakeAwareData, gh.Kernel.IGH_PreviewData):
"""A Text object that can be baked and transformed in Grasshopper.
The code for this entire class was taken from David Rutten and Giulio Piacentino's
script described here:
https://discourse.mcneel.com/t/creating-text-objects-and-outputting-them-as-normal-rhino-geometry/47834/7
Args:
text: A Rhino Text3d object.
"""
def __init__(self, text):
"""Initialize Bake-able text."""
self.m_value = text
[docs]
@staticmethod
def DuplicateText3d(original):
if original is None:
return None
text = rh.Display.Text3d(original.Text, original.TextPlane, original.Height)
text.Bold = original.Bold
text.Italic = original.Italic
text.FontFace = original.FontFace
return text
[docs]
def DuplicateGeometry(self):
return TextGoo(TextGoo.DuplicateText3d(self.m_value))
[docs]
def get_TypeName(self):
return "3D Text"
[docs]
def get_TypeDescription(self):
return "3D Text"
[docs]
def get_Boundingbox(self):
if self.m_value is None:
return rh.Geometry.BoundingBox.Empty
return self.m_value.BoundingBox
[docs]
def GetBoundingBox(self, xform):
if self.m_value is None:
return rh.Geometry.BoundingBox.Empty
box = self.m_value.BoundingBox
corners = xform.TransformList(box.GetCorners())
return rh.Geometry.BoundingBox(corners)
[docs]
def Transform(self, xform):
text = TextGoo.DuplicateText3d(self.m_value)
if text is None:
return TextGoo(None)
plane = text.TextPlane
point = plane.PointAt(1, 1)
plane.Transform(xform)
point.Transform(xform)
dd = point.DistanceTo(plane.Origin)
text.TextPlane = plane
text.Height *= dd / math.sqrt(2)
new_text = TextGoo(text)
new_text.m_value.Bold = self.m_value.Bold
new_text.m_value.Italic = self.m_value.Italic
new_text.m_value.FontFace = self.m_value.FontFace
return new_text
[docs]
def Morph(self, xmorph):
return self.DuplicateGeometry()
[docs]
def get_ClippingBox(self):
return self.get_Boundingbox()
[docs]
def DrawViewportWires(self, args):
if self.m_value is None:
return
color = black() if black is not None else args.Color
args.Pipeline.Draw3dText(self.m_value, color)
[docs]
def DrawViewportMeshes(self, args):
# Do not draw in meshing layer.
pass
[docs]
def BakeGeometry(self, doc, att, id):
id = guid.Empty
if self.m_value is None:
return False, id
if att is None:
att = doc.CreateDefaultAttributes()
original_plane = None
d_txt = self.m_value.Text
nl_count = len(d_txt.split('\n')) - 1
if nl_count > 1 and str(self.m_value.VerticalAlignment) == 'Bottom':
y_ax = rh.Geometry.Vector3d(self.m_value.TextPlane.YAxis)
txt_h = self.m_value.Height * (3 / 2)
m_vec = rh.Geometry.Vector3d.Multiply(y_ax, txt_h * -nl_count)
original_plane = self.m_value.TextPlane
new_plane = rh.Geometry.Plane(self.m_value.TextPlane)
new_plane.Translate(m_vec)
self.m_value.TextPlane = new_plane
self.m_value.Height = self.m_value.Height
doc.ModelSpaceAnnotationScalingEnabled = False # disable model scale
id = doc.Objects.AddText(self.m_value, att)
self.m_value.Height = self.m_value.Height
if original_plane is not None:
self.m_value.TextPlane = original_plane
return True, id
[docs]
def ScriptVariable(self):
"""Overwrite Grasshopper ScriptVariable method."""
return self
[docs]
def ToString(self):
"""Overwrite .NET ToString method."""
return self.__repr__()
def __repr__(self):
if self.m_value is None:
return "<null>"
return self.m_value.Text
[docs]
class AlignmentTypes(object):
"""Enumeration of text alignment types."""
_HORIZONTAL = (rh.DocObjects.TextHorizontalAlignment.Left,
rh.DocObjects.TextHorizontalAlignment.Center,
rh.DocObjects.TextHorizontalAlignment.Right)
_VERTICAL = (rh.DocObjects.TextVerticalAlignment.Top,
rh.DocObjects.TextVerticalAlignment.MiddleOfTop,
rh.DocObjects.TextVerticalAlignment.BottomOfTop,
rh.DocObjects.TextVerticalAlignment.Middle,
rh.DocObjects.TextVerticalAlignment.MiddleOfBottom,
rh.DocObjects.TextVerticalAlignment.Bottom,
rh.DocObjects.TextVerticalAlignment.BottomOfBoundingBox)
[docs]
@classmethod
def horizontal(cls, field_number):
"""Get a Rhino horizontal alignment object by its integer field number.
* 0 - Left
* 1 - Center
* 2 - Right
"""
return cls._HORIZONTAL[field_number]
[docs]
@classmethod
def vertical(cls, field_number):
"""Get a Rhino vertical alignment object by its integer field number.
* 0 - Top
* 1 - MiddleOfTop
* 2 - BottomOfTop
* 3 - Middle
* 4 - MiddleOfBottom
* 5 - Bottom
* 6 - BottomOfBoundingBox
"""
return cls._VERTICAL[field_number]