"""Classes to preview things in the Rhino Display Pipeline."""
from __future__ import division
from ladybug_geometry.geometry2d import Vector2D, Point2D, Ray2D, LineSegment2D, \
Polyline2D, Arc2D, Polygon2D, Mesh2D
from ladybug_geometry.geometry3d import Vector3D, Point3D, Ray3D, Plane, LineSegment3D, \
Polyline3D, Arc3D, Face3D, Mesh3D, Polyface3D, Sphere, Cone, Cylinder
from ladybug.graphic import GraphicContainer
from ladybug_display.altnumber import Default
from ladybug_display.geometry3d import DisplayText3D
from ladybug_display.visualization import AnalysisGeometry
from .config import units_system
from .color import color_to_color, argb_color_to_color, black
from .fromgeometry import from_point2d, from_vector2d, from_ray2d, \
from_arc2d, from_polygon2d, from_polyline2d, from_mesh2d, \
from_point3d, from_vector3d, from_ray3d, from_plane, \
from_arc3d, from_polyline3d, from_mesh3d, from_face3d, from_polyface3d, \
from_sphere, from_cone, from_cylinder
try:
import System
except ImportError as e:
raise ImportError("Failed to import Windows/.NET libraries\n{}".format(e))
try:
import Rhino.Geometry as rg
import Rhino.Display as rd
import Rhino.DocObjects as ro
except ImportError as e:
raise ImportError('Failed to import Rhino.\n{}'.format(e))
try:
import scriptcontext as sc
except ImportError:
pass # previewing 2D legends will not be available
[docs]
class VisualizationSetConduit(rd.DisplayConduit):
"""Class to preview VisualizationSet in the Rhino Display pipeline.
Args:
visualization_set: A Ladybug Display VisualizationSet object to be translated
into arguments for the Rhino display pipeline.
render_3d_legend: A Boolean to note whether the VisualizationSet should be
rendered with 3D legends for any AnalysisGeometries it
includes. (Default: False).
render_2d_legend: A Boolean to note whether the VisualizationSet should be
rendered with 2D screen-oriented legends for any AnalysisGeometries it
includes. (Default: False).
"""
def __init__(self, visualization_set, render_3d_legend=False, render_2d_legend=False):
"""Initialize VisualizationSetConduit."""
# set the primary properties
self.vis_con = VisualizationSetConverter(
visualization_set, render_3d_legend, render_2d_legend)
[docs]
def CalculateBoundingBox(self, calculateBoundingBoxEventArgs):
"""Overwrite the method that passes the bounding box to the display."""
calculateBoundingBoxEventArgs.IncludeBoundingBox(self.vis_con.bbox)
[docs]
def DrawForeground(self, drawEventArgs):
"""Overwrite the method that draws the objects in the display."""
# get the DisplayPipeline from the event arguments
display = drawEventArgs.Display
# for each object to be rendered, pass the drawing arguments
for draw_args in self.vis_con.draw_2d_text:
display.Draw2dText(*draw_args)
for draw_args in self.vis_con.draw_sprite:
display.DrawSprite(*draw_args)
[docs]
def PreDrawObjects(self, drawEventArgs):
"""Overwrite the method that draws the objects in the display."""
# get the DisplayPipeline from the event arguments
display = drawEventArgs.Display
# for each object to be rendered, pass the drawing arguments
for draw_args in self.vis_con.draw_mesh_false_colors:
display.DrawMeshFalseColors(draw_args)
for draw_args in self.vis_con.draw_mesh_shaded:
display.DrawMeshFalseColors(draw_args[0])
for draw_args in self.vis_con.draw_brep_shaded:
display.DrawBrepShaded(*draw_args)
[docs]
def PostDrawObjects(self, drawEventArgs):
"""Overwrite the method that draws the objects in the display."""
# get the DisplayPipeline from the event arguments
display = drawEventArgs.Display
# for each object to be rendered, pass the drawing arguments
for draw_args in self.vis_con.draw_3d_text:
display.Draw3dText(*draw_args)
for draw_args in self.vis_con.draw_mesh_wires:
display.DrawMeshWires(*draw_args)
for draw_args in self.vis_con.draw_mesh_vertices:
display.DrawMeshVertices(*draw_args)
for draw_args in self.vis_con.draw_point:
display.DrawPoint(*draw_args)
for draw_args in self.vis_con.draw_arrow:
display.DrawArrow(*draw_args)
for draw_args in self.vis_con.draw_brep_wires:
display.DrawBrepWires(*draw_args)
for draw_args in self.vis_con.draw_line:
display.DrawLine(*draw_args)
for draw_args in self.vis_con.draw_patterned_line:
display.DrawPatternedLine(*draw_args)
for draw_args in self.vis_con.draw_patterned_polyline:
display.DrawPatternedPolyline(*draw_args)
for draw_args in self.vis_con.draw_curve:
display.DrawCurve(*draw_args)
for draw_args in self.vis_con.draw_circle:
display.DrawCircle(*draw_args)
for draw_args in self.vis_con.draw_arc:
display.DrawArc(*draw_args)
for draw_args in self.vis_con.draw_sphere:
display.DrawSphere(*draw_args)
for draw_args in self.vis_con.draw_cone:
display.DrawCone(*draw_args)
for draw_args in self.vis_con.draw_cylinder:
display.DrawCylinder(*draw_args)
[docs]
class VisualizationSetConverter(object):
"""Class to translate VisualizationSets to arguments for the Rhino display pipeline.
Args:
visualization_set: A Ladybug Display VisualizationSet object to be translated
into arguments for the Rhino display pipeline.
render_3d_legend: A Boolean to note whether the VisualizationSet should be
rendered with 3D legends for any AnalysisGeometries it
includes. (Default: False).
render_2d_legend: A Boolean to note whether the VisualizationSet should be
rendered with 2D screen-oriented legends for any AnalysisGeometries it
includes. (Default: False).
Properties:
* vis_set
* render_3d_legend
* render_2d_legend
* min_pt
* max_pt
* bbox
* draw_sprite
* draw_2d_text
* draw_3d_text
* draw_mesh_false_colors
* draw_mesh_shaded
* draw_mesh_wires
* draw_mesh_vertices
* draw_brep_shaded
* draw_brep_wires
* draw_point
* draw_arrow
* draw_line
* draw_patterned_line
* draw_patterned_polyline
* draw_curve
* draw_circle
* draw_arc
* draw_sphere
* draw_cone
* draw_cylinder
"""
TEXT_HORIZ = {
'Left': ro.TextHorizontalAlignment.Left,
'Center': ro.TextHorizontalAlignment.Center,
'Right': ro.TextHorizontalAlignment.Right
}
TEXT_VERT = {
'Top': ro.TextVerticalAlignment.Top,
'Middle': ro.TextVerticalAlignment.Middle,
'Bottom': ro.TextVerticalAlignment.Bottom
}
LINE_TYPE = {
'Dashed': int('0x1C7', base=16),
'Dotted': int('0x00001111', base=16),
'DashDot': int('0x1F11F1', base=16)
}
def __init__(
self, visualization_set, render_3d_legend=False, render_2d_legend=False):
"""Initialize VisualizationSetConverter."""
# set the primary properties
self.vis_set = visualization_set
self.render_3d_legend = bool(render_3d_legend)
self.render_2d_legend = bool(render_2d_legend)
# get the active viewport width and height if 2D legends are requested
if self.render_2d_legend:
active_view = sc.doc.Views.ActiveView.ActiveViewport
v_size = active_view.Size
self.view_width = v_size.Width
self.view_height = v_size.Height
else: # just use some defaults as it's probably not critical
self.view_width, self.view_height = 800, 600
# ensure the visualization set is in Rhino model units
units_sys = units_system()
if self.vis_set.units is not None and units_sys is not None \
and self.vis_set.units != units_sys:
self.vis_set.convert_to_units(units_sys)
# set up the bounding box and min/max point
self.min_pt = self.vis_set.min_point
self.max_pt = self.vis_set.max_point
if self.render_3d_legend: # leave extra room for legend
center = Point3D(
(self.min_pt.x + self.max_pt.x) / 2,
(self.min_pt.y + self.max_pt.y) / 2,
(self.min_pt.z + self.max_pt.z) / 2)
self.bbox = rg.BoundingBox(
from_point3d(self.min_pt.scale(2, center)),
from_point3d(self.max_pt.scale(2, center)))
else:
self.bbox = rg.BoundingBox(
from_point3d(self.min_pt), from_point3d(self.max_pt))
# translate all of the rhino objects to be rendered in the scene
self.translate_objects()
self.sort_shaded_objects()
[docs]
def translate_objects(self):
"""Translate all of the objects in the VisualizationSet into a Rhino equivalent.
This is a necessary pre-step before frames of the visualization set
can be rendered in the display pipeline.
"""
# initialize all of the lists to hold the drawing arguments
self.draw_sprite = []
self.draw_2d_text = []
self.draw_3d_text = []
self.draw_mesh_false_colors = []
self.draw_mesh_shaded = []
self.draw_mesh_wires = []
self.draw_mesh_vertices = []
self.draw_brep_shaded = []
self.draw_brep_wires = []
self.draw_point = []
self.draw_arrow = []
self.draw_line = []
self.draw_patterned_line = []
self.draw_patterned_polyline = []
self.draw_curve = []
self.draw_circle = []
self.draw_arc = []
self.draw_sphere = []
self.draw_cone = []
self.draw_cylinder = []
# loop through visualization geometry objects and draw them
default_leg_x3d, default_leg_x2d, default_leg_y2d = 0, 10, 50
for geo in self.vis_set.geometry:
if geo.hidden:
continue
# translate it as AnalysisGeometry if specified
if isinstance(geo, AnalysisGeometry):
# generate the colors that correspond to the values
data = geo.data_sets[geo.active_data]
graphic = GraphicContainer(
data.values, self.min_pt, self.max_pt,
data.legend_parameters, data.data_type, data.unit)
colors = graphic.value_colors
# translate the analysis geometry using the matching method
if geo.matching_method == 'faces':
c_count = 0
for mesh in geo.geometry:
mesh.colors = colors[c_count:c_count + len(mesh.faces)]
c_count += len(mesh.faces)
self.translate_analysis_mesh(mesh, geo.display_mode)
elif geo.matching_method == 'vertices':
c_count = 0
for mesh in geo.geometry:
mesh.colors = colors[c_count:c_count + len(mesh.vertices)]
c_count += len(mesh.vertices)
self.translate_analysis_mesh(mesh, geo.display_mode)
else: # one color per geometry object
for geo_obj, col in zip(geo.geometry, colors):
self.translate_analysis_geometry(
geo_obj, col, geo.display_mode)
# if the object is set to translate 3D legends, then display it
if self.render_3d_legend:
# ensure multiple legends are not on top of each other
if graphic.legend_parameters.is_base_plane_default:
l_par = graphic.legend_parameters
m_vec = Vector3D(default_leg_x3d, 0, 0)
l_par.base_plane = l_par.base_plane.move(m_vec)
l_par.properties_3d._is_base_plane_default = True
leg_width = l_par.segment_width + 6 * l_par.text_height \
if l_par.vertical else \
l_par.segment_width * (l_par.segment_count + 2)
default_leg_x3d += leg_width
self.translate_legend3d(graphic.legend)
# if the object is set to translate 2D legends, then display it
if self.render_2d_legend:
# ensure multiple legends are not on top of each other
l_par = graphic.legend_parameters
if l_par.vertical and l_par.is_origin_x_default:
l_par.origin_x = '{}px'.format(default_leg_x2d)
l_par.properties_2d._is_origin_x_default = True
sw = graphic.legend.parse_dim_2d(
l_par.segment_width_2d, self.view_width)
th = graphic.legend.parse_dim_2d(
l_par.text_height_2d, self.view_height)
leg_width = sw + 6 * th
default_leg_x2d += leg_width
elif not l_par.vertical and l_par.is_origin_y_default:
l_par.origin_y = '{}px'.format(default_leg_y2d)
l_par.properties_2d._is_origin_y_default = True
sh = graphic.legend.parse_dim_2d(
l_par.segment_height_2d, self.view_height)
th = graphic.legend.parse_dim_2d(
l_par.text_height_2d, self.view_height)
leg_height = sh + 4 * th
default_leg_y2d += leg_height
self.translate_legend2d(graphic.legend)
else: # it's a ContextGeometry object
for display_obj in geo.geometry:
if isinstance(display_obj, DisplayText3D):
self.translate_display_text3d(display_obj)
else:
self.translate_context_geometry(display_obj)
[docs]
def translate_display_text3d(self, text_obj):
"""Translate ladybug DisplayText3D into arguments for drawing in the scene.
Args:
text_obj: The ladybug DisplayText3D to be translated.
"""
self.draw_3d_text.append((
text_obj.text, color_to_color(text_obj.color), from_plane(text_obj.plane),
text_obj.height, text_obj.font, False, False,
self.TEXT_HORIZ[text_obj.horizontal_alignment],
self.TEXT_VERT[text_obj.vertical_alignment]))
[docs]
def translate_legend3d(self, legend):
"""Translate a ladybug Legend into arguments for drawing in the scene.
Args:
legend: A Ladybug Legend object to be converted to Rhino geometry.
"""
# translate the legend mesh
rh_mesh = from_mesh3d(legend.segment_mesh)
self.draw_mesh_false_colors.append(rh_mesh)
self.draw_mesh_wires.append((rh_mesh, black()))
# translate the legend text
_height = legend.legend_parameters.text_height
_font = legend.legend_parameters.font
if legend.legend_parameters.continuous_legend is False:
legend_text = [
DisplayText3D(txt, loc, _height, None, _font, 'Left', 'Bottom')
for txt, loc in zip(legend.segment_text, legend.segment_text_location)]
elif legend.legend_parameters.vertical is True:
legend_text = [
DisplayText3D(txt, loc, _height, None, _font, 'Left', 'Middle')
for txt, loc in zip(legend.segment_text, legend.segment_text_location)]
else:
legend_text = [
DisplayText3D(txt, loc, _height, None, _font, 'Center', 'Bottom')
for txt, loc in zip(legend.segment_text, legend.segment_text_location)]
legend_title = DisplayText3D(
legend.title, legend.title_location, _height, None, _font)
legend_text.insert(0, legend_title)
for txt_obj in legend_text:
self.translate_display_text3d(txt_obj)
[docs]
def translate_legend2d(self, legend):
"""Translate a ladybug Legend into arguments for drawing in the scene.
Args:
legend: A Ladybug Legend object to be converted to 2D
screen-oriented geometry.
"""
d_sprite, d_2d_text = self.convert_legend2d(
legend, self.view_width, self.view_height)
self.draw_sprite.append(d_sprite)
self.draw_2d_text.extend(d_2d_text)
[docs]
def translate_analysis_mesh(self, mesh, display_mode):
"""Translate an analysis mesh into arguments for drawing in the scene.
Args:
mesh: The Ladybug Mesh3D or Mesh2D object to be translated.
display_mode: Text for the display mode in which to translate the mesh.
"""
if display_mode in ('Surface', 'SurfaceWithEdges'):
rh_mesh = from_mesh3d(mesh) if isinstance(mesh, Mesh3D) \
else from_mesh2d(mesh)
self.draw_mesh_false_colors.append(rh_mesh)
if display_mode == 'SurfaceWithEdges':
self.draw_mesh_wires.append((rh_mesh, black()))
elif display_mode == 'Wireframe':
rh_mesh = from_mesh3d(mesh) if isinstance(mesh, Mesh3D) \
else from_mesh2d(mesh)
self.draw_mesh_wires.append((rh_mesh, black()))
elif display_mode == 'Points':
if isinstance(mesh, Mesh3D):
points = [from_point3d(pt) for pt in mesh.face_centroids] \
if mesh.is_color_by_face else \
[from_point3d(pt) for pt in mesh.vertices]
else:
points = [from_point2d(pt) for pt in mesh.face_centroids] \
if mesh.is_color_by_face else \
[from_point2d(pt) for pt in mesh.vertices]
colors = [color_to_color(col) for col in mesh.colors]
for col, pt in zip(colors, points):
self.draw_point.append((pt, rd.PointStyle.RoundSimple, 3, col))
[docs]
def translate_analysis_geometry(self, geo_obj, color, display_mode):
"""Translate analysis geometry objects into arguments for drawing in the scene.
Args:
geo_obj: The Ladybug Geometry object to be translated.
color: The Ladybug Color object with which the object will be translated.
display_mode: Text for the display mode in which to translate the mesh.
"""
# translate the color
col = color_to_color(color)
if isinstance(geo_obj, (Point3D, Point2D)):
# translate analysis point
pt = from_point3d(geo_obj) if isinstance(geo_obj, Point3D) \
else from_point2d(geo_obj)
self.draw_point.append((pt, rd.PointStyle.RoundSimple, 5, col))
elif isinstance(geo_obj, (LineSegment3D, LineSegment2D)):
# translate analysis line segment
if isinstance(geo_obj, LineSegment3D):
pt1, pt2 = from_point3d(geo_obj.p1), from_point3d(geo_obj.p2)
else:
pt1, pt2 = from_point2d(geo_obj.p1), from_point2d(geo_obj.p2)
self.draw_line.append((pt1, pt2, col, 3))
elif isinstance(geo_obj, (Polyline3D, Polyline2D)):
# translate analysis polyline
crv = from_polyline3d(geo_obj) if isinstance(geo_obj, Polyline3D) \
else from_polyline2d(geo_obj)
self.draw_curve.append((crv, col, 3))
elif isinstance(geo_obj, (Face3D, Polyface3D)):
# translate analysis Face3D and Polyface3D
if display_mode in ('Surface', 'SurfaceWithEdges'):
mat = rd.DisplayMaterial(col)
rh_obj = from_face3d(geo_obj) if isinstance(geo_obj, Face3D) \
else from_polyface3d(geo_obj)
self.draw_brep_shaded.append((rh_obj, mat))
if display_mode == 'SurfaceWithEdges':
self.draw_brep_wires.append((rh_obj, black(), -1))
elif display_mode == 'Wireframe':
rh_obj = from_face3d(geo_obj) if isinstance(geo_obj, Face3D) \
else from_polyface3d(geo_obj)
self.draw_brep_wires.append((rh_obj, col, 1))
elif display_mode == 'Points':
for pt in geo_obj.vertices:
self.draw_point.append(
(from_point3d(pt), rd.PointStyle.RoundSimple, 3, col))
elif isinstance(geo_obj, (Mesh3D, Mesh2D)):
# translate analysis mesh
rh_obj = from_mesh3d(geo_obj) if isinstance(geo_obj, Mesh3D) \
else from_mesh2d(geo_obj)
if display_mode in ('Surface', 'SurfaceWithEdges'):
mat = rd.DisplayMaterial(col)
rh_obj.VertexColors.CreateMonotoneMesh(col)
self.draw_mesh_shaded.append((rh_obj, mat))
if display_mode == 'SurfaceWithEdges':
self.draw_mesh_wires.append((rh_obj, black(), 1))
elif display_mode == 'Wireframe':
self.draw_mesh_wires.append((rh_obj, col, 3))
elif display_mode == 'Points':
self.draw_mesh_vertices.append((rh_obj, col))
elif isinstance(geo_obj, (Ray2D, Ray3D)):
# translate analysis rays
rh_ray = from_ray3d(geo_obj) if isinstance(geo_obj, Ray3D) \
else from_ray2d(geo_obj)
rh_obj = rg.Line(rh_ray.Position, rh_ray.Direction)
self.draw_arrow.append((rh_obj, col))
elif isinstance(geo_obj, Sphere):
# translate analysis sphere
if display_mode in ('Surface', 'SurfaceWithEdges'):
rh_obj, mat = from_sphere(geo_obj), rd.DisplayMaterial(col)
self.draw_brep_shaded.append((rh_obj.ToBrep(), mat))
if display_mode == 'SurfaceWithEdges':
self.draw_sphere.append((rh_obj, black()))
elif display_mode == 'Wireframe':
self.draw_sphere.append((from_sphere(geo_obj), col))
elif display_mode == 'Points':
pt_arg = (from_point3d(geo_obj.center),
rd.PointStyle.RoundSimple, 3, col)
self.draw_point.append(pt_arg)
elif isinstance(geo_obj, (Vector2D, Vector3D)):
# translate analysis vectors
rh_vec = from_vector3d(geo_obj) if isinstance(geo_obj, Vector3D) \
else from_vector2d(geo_obj)
rh_obj = rg.Line(rg.Point3d(0, 0, 0), rh_vec)
self.draw_arrow.append((rh_obj, col))
elif isinstance(geo_obj, Polygon2D):
# translate analysis polygon
self.draw_curve.append((from_polygon2d(geo_obj), col, 3))
elif isinstance(geo_obj, (Arc3D, Arc2D)):
# translate analysis arcs
crv = from_arc3d(geo_obj) if isinstance(geo_obj, Arc3D) \
else from_arc2d(geo_obj)
if geo_obj.is_circle:
self.draw_circle.append((crv, col, 3))
else:
self.draw_arc.append((crv, col, 3))
elif isinstance(geo_obj, Cone):
# translate analysis cone
if display_mode in ('Surface', 'SurfaceWithEdges'):
rh_obj, mat = from_cone(geo_obj), rd.DisplayMaterial(col)
self.draw_brep_shaded.append((rh_obj.ToBrep(True), mat))
if display_mode == 'SurfaceWithEdges':
self.draw_cone.append((rh_obj, black()))
elif display_mode == 'Wireframe':
self.draw_cone.append((from_cone(geo_obj), col))
elif display_mode == 'Points':
pt_arg = (from_point3d(geo_obj.vertex),
rd.PointStyle.RoundSimple, 3, col)
self.draw_point.append(pt_arg)
elif isinstance(geo_obj, Cylinder):
# translate analysis cylinder
if display_mode in ('Surface', 'SurfaceWithEdges'):
rh_obj, mat = from_cylinder(geo_obj), rd.DisplayMaterial(col)
self.draw_brep_shaded.append((rh_obj.ToBrep(True, True), mat))
if display_mode == 'SurfaceWithEdges':
self.draw_cylinder.append((rh_obj, black()))
elif display_mode == 'Wireframe':
self.draw_cylinder.append((from_cylinder(geo_obj), col))
elif display_mode == 'Points':
pt_arg = (from_point3d(geo_obj.center),
rd.PointStyle.RoundSimple, 3, col)
self.draw_point.append(pt_arg)
elif isinstance(geo_obj, Plane):
# translate analysis planes
pln = from_plane(geo_obj)
r = 10 # default radius for a plane object in rhino model units
# grid lines
for j in range(-5, 6):
i = j / 5
p0 = pln.PointAt(i * r, -r)
p1 = pln.PointAt(i * r, r)
self.draw_line.append((p0, p1, col, 1))
p0 = pln.PointAt(-r, i * r)
p1 = pln.PointAt(r, i * r)
self.draw_line.append((p0, p1, col, 1))
# axes
self.draw_line.append((pln.Origin, pln.Origin + pln.XAxis * r, col, 3))
self.draw_line.append((pln.Origin, pln.Origin + pln.YAxis * r, col, 3))
[docs]
def translate_context_geometry(self, dis_obj):
"""Translate a display geometry object into arguments for drawing in the scene.
Args:
dis_obj: The Ladybug Display geometry object to be translated.
"""
# first translate the color and get the geometry object
col = color_to_color(dis_obj.color)
geo_obj = dis_obj.geometry
if isinstance(geo_obj, (Point3D, Point2D)):
# translate display point
pt = from_point3d(geo_obj) if isinstance(geo_obj, Point3D) \
else from_point2d(geo_obj)
radius = 3 if isinstance(dis_obj.radius, Default) else int(dis_obj.radius)
self.draw_point.append((pt, rd.PointStyle.RoundSimple, radius, col))
elif isinstance(geo_obj, (LineSegment3D, LineSegment2D)):
# translate display line segment
if isinstance(geo_obj, LineSegment3D):
pt1, pt2 = from_point3d(geo_obj.p1), from_point3d(geo_obj.p2)
else:
pt1, pt2 = from_point2d(geo_obj.p1), from_point2d(geo_obj.p2)
lw = 1 if isinstance(dis_obj.line_width, Default) \
else int(dis_obj.line_width)
if dis_obj.line_type == 'Continuous':
self.draw_line.append((pt1, pt2, col, lw))
else:
self.draw_patterned_line.append(
(pt1, pt2, col, self.LINE_TYPE[dis_obj.line_type], lw))
elif isinstance(geo_obj, (Polyline3D, Polyline2D)):
# translate display polyline
lw = 1 if isinstance(dis_obj.line_width, Default) \
else int(dis_obj.line_width)
if dis_obj.line_type == 'Continuous':
crv = from_polyline3d(geo_obj) if isinstance(geo_obj, Polyline3D) \
else from_polyline2d(geo_obj)
self.draw_curve.append((crv, col, lw))
else: # ensure the line pattern is respected
verts = [from_point3d(pt) for pt in geo_obj.vertices] \
if isinstance(geo_obj, Polyline3D) else \
[from_point2d(pt) for pt in geo_obj.vertices]
self.draw_patterned_polyline.append(
(verts, col, self.LINE_TYPE[dis_obj.line_type], lw, False))
elif isinstance(geo_obj, (Ray2D, Ray3D)):
# translate display rays
rh_ray = from_ray3d(geo_obj) if isinstance(geo_obj, Ray3D) \
else from_ray2d(geo_obj)
rh_obj = rg.Line(rh_ray.Position, rh_ray.Direction)
self.draw_arrow.append((rh_obj, col))
elif isinstance(geo_obj, (Face3D, Polyface3D)):
# translate display Face3D and Polyface3D
if dis_obj.display_mode in ('Surface', 'SurfaceWithEdges'):
mat = rd.DisplayMaterial(col, 1 - (dis_obj.color.a / 255))
rh_obj = from_face3d(geo_obj) if isinstance(geo_obj, Face3D) \
else from_polyface3d(geo_obj)
self.draw_brep_shaded.append((rh_obj, mat))
if dis_obj.display_mode == 'SurfaceWithEdges':
self.draw_brep_wires.append((rh_obj, black(), -1))
elif dis_obj.display_mode == 'Wireframe':
rh_obj = from_face3d(geo_obj) if isinstance(geo_obj, Face3D) \
else from_polyface3d(geo_obj)
self.draw_brep_wires.append((rh_obj, col, 1))
elif dis_obj.display_mode == 'Points':
for pt in geo_obj.vertices:
self.draw_point.append(
(from_point3d(pt), rd.PointStyle.RoundSimple, 3, col))
elif isinstance(geo_obj, (Mesh3D, Mesh2D)):
# translate display mesh
rh_obj = from_mesh3d(geo_obj) if isinstance(geo_obj, Mesh3D) \
else from_mesh2d(geo_obj)
if dis_obj.display_mode in ('Surface', 'SurfaceWithEdges'):
mat = rd.DisplayMaterial(col, 1 - (dis_obj.color.a / 255))
t_color = argb_color_to_color(dis_obj.color)
rh_obj.VertexColors.CreateMonotoneMesh(t_color)
self.draw_mesh_shaded.append((rh_obj, mat))
if dis_obj.display_mode == 'SurfaceWithEdges':
self.draw_mesh_wires.append((rh_obj, black(), 1))
elif dis_obj.display_mode == 'Wireframe':
self.draw_mesh_wires.append((rh_obj, col, 1))
elif dis_obj.display_mode == 'Points':
self.draw_mesh_vertices.append((rh_obj, col))
elif isinstance(geo_obj, Sphere):
# translate analysis sphere
if dis_obj.display_mode in ('Surface', 'SurfaceWithEdges'):
rh_obj = from_sphere(geo_obj)
mat = rd.DisplayMaterial(col, 1 - (dis_obj.color.a / 255))
self.draw_brep_shaded.append((rh_obj.ToBrep(), mat))
if dis_obj.display_mode == 'SurfaceWithEdges':
self.draw_sphere.append((rh_obj, black()))
elif dis_obj.display_mode == 'Wireframe':
self.draw_sphere.append((from_sphere(geo_obj), col))
elif dis_obj.display_mode == 'Points':
pt_arg = (from_point3d(geo_obj.center),
rd.PointStyle.RoundSimple, 3, col)
self.draw_point.append(pt_arg)
elif isinstance(geo_obj, Polygon2D):
# translate display polygon
lw = 1 if isinstance(dis_obj.line_width, Default) \
else int(dis_obj.line_width)
if dis_obj.line_type == 'Continuous':
self.draw_curve.append((from_polygon2d(geo_obj), col, lw))
else: # ensure the line pattern is respected
verts = [from_point2d(pt) for pt in geo_obj.vertices]
self.draw_patterned_polyline.append(
(verts, col, self.LINE_TYPE[dis_obj.line_type], lw, True))
elif isinstance(geo_obj, (Arc3D, Arc2D)):
# translate display arc
lw = 1 if isinstance(dis_obj.line_width, Default) \
else int(dis_obj.line_width)
if dis_obj.line_type == 'Continuous':
crv = from_arc3d(geo_obj) if isinstance(geo_obj, Arc3D) else \
from_arc2d(geo_obj)
if geo_obj.is_circle:
self.draw_circle.append((crv, col, lw))
else:
self.draw_arc.append((crv, col, lw))
else: # ensure the line pattern is respected
p_line = geo_obj.to_polyline(
int(abs(geo_obj.a2 - geo_obj.a1) / 0.0523599))
if geo_obj.is_circle:
arc_verts, closed = p_line.vertices[:-1], True
else:
arc_verts, closed = p_line.vertices, False
verts = [from_point3d(pt) for pt in arc_verts] \
if isinstance(p_line, Polyline3D) else \
[from_point2d(pt) for pt in arc_verts]
self.draw_patterned_polyline.append(
(verts, col, self.LINE_TYPE[dis_obj.line_type], lw, closed))
elif isinstance(geo_obj, Cone):
# translate analysis cone
if dis_obj.display_mode in ('Surface', 'SurfaceWithEdges'):
rh_obj = from_cone(geo_obj)
mat = rd.DisplayMaterial(col, 1 - (dis_obj.color.a / 255))
self.draw_brep_shaded.append((rh_obj.ToBrep(True), mat))
if dis_obj.display_mode == 'SurfaceWithEdges':
self.draw_cone.append((rh_obj, black()))
elif dis_obj.display_mode == 'Wireframe':
self.draw_cone.append((from_cone(geo_obj), col))
elif dis_obj.display_mode == 'Points':
pt_arg = (from_point3d(geo_obj.vertex),
rd.PointStyle.RoundSimple, 3, col)
self.draw_point.append(pt_arg)
elif isinstance(geo_obj, Cylinder):
# translate analysis cylinder
if dis_obj.display_mode in ('Surface', 'SurfaceWithEdges'):
rh_obj = from_cylinder(geo_obj)
mat = rd.DisplayMaterial(col, 1 - (dis_obj.color.a / 255))
self.draw_brep_shaded.append((rh_obj.ToBrep(True, True), mat))
if dis_obj.display_mode == 'SurfaceWithEdges':
self.draw_cylinder.append((rh_obj, black()))
elif dis_obj.display_mode == 'Wireframe':
self.draw_cylinder.append((from_cylinder(geo_obj), col))
elif dis_obj.display_mode == 'Points':
pt_arg = (from_point3d(geo_obj.center),
rd.PointStyle.RoundSimple, 3, col)
self.draw_point.append(pt_arg)
elif isinstance(geo_obj, Plane):
# translate analysis planes
pln = from_plane(geo_obj)
r = 10 # default radius for a plane object in rhino model units
# grid lines
if dis_obj.show_grid:
for j in range(-5, 6):
i = j / 5
p0 = pln.PointAt(i * r, -r)
p1 = pln.PointAt(i * r, r)
self.draw_line.append((p0, p1, col, 1))
p0 = pln.PointAt(-r, i * r)
p1 = pln.PointAt(r, i * r)
self.draw_line.append((p0, p1, col, 1))
# axes
if dis_obj.show_axes:
self.draw_line.append((pln.Origin, pln.Origin + pln.XAxis * r, col, 3))
self.draw_line.append((pln.Origin, pln.Origin + pln.YAxis * r, col, 3))
[docs]
def sort_shaded_objects(self):
"""Sort shaded objects according to their transparency.
This ensures that the resulting display has visible objects behind
any transparent objects.
"""
if len(self.draw_brep_shaded) != 0:
trans = (args[1].Transparency for args in self.draw_brep_shaded)
self.draw_brep_shaded = \
[a for _, a in sorted(zip(trans, self.draw_brep_shaded))]
if len(self.draw_mesh_shaded) != 0:
trans = (args[1].Transparency for args in self.draw_mesh_shaded)
self.draw_mesh_shaded = \
[a for _, a in sorted(zip(trans, self.draw_mesh_shaded))]
[docs]
@staticmethod
def convert_legend2d(legend, vw=None, vh=None):
"""Convert a ladybug Legend into arguments for drawing in 2D on the screen.
Args:
legend: A Ladybug Legend object to be converted to 2D screen-oriented
geometry.
vw: An integer for the view width in pixels. If None, it will
be obtained from the active viewport. (Default: None).
vh: An integer for the view height in pixels. If None, it will
be obtained from the active viewport. (Default: None).
Returns:
A tuple with two values needed to render the legend in the 2D scene:
- legend_mesh -- A colored mesh for the legend.
- legend_title -- A text object for the legend title.
"""
# figure out the dimensions of the active viewport
if vw is None or vh is None:
active_view = sc.doc.Views.ActiveView.ActiveViewport
v_size = active_view.Size
vw = v_size.Width if vw is None else vw
vh = v_size.Height if vh is None else vh
# translate the color matrix to a bitmap
l_par = legend.legend_parameters
color_mtx = legend.color_map_2d(vw, vh)
color_mtx = [[color_to_color(c) for c in row] for row in color_mtx]
net_bm = System.Drawing.Bitmap(len(color_mtx[0]), len(color_mtx))
for y, row in enumerate(color_mtx):
for x, col in enumerate(row):
net_bm.SetPixel(x, y, col)
rh_bm = rd.DisplayBitmap(net_bm)
or_x, or_y, sh, sw, th = legend._pixel_dims_2d(vw, vh)
s_count = l_par.segment_count
s_count = s_count - 1 if l_par.continuous_legend else s_count
leg_width = sw if l_par.vertical else sw * s_count
leg_height = sh if not l_par.vertical else sh * s_count
cent_pt = rg.Point2d(or_x + (leg_width / 2), or_y + (leg_height / 2))
draw_sprite = (rh_bm, cent_pt, leg_width, leg_height)
# translate the legend text
_height = legend.parse_dim_2d(l_par.text_height_2d, vh)
_font = l_par.font
txt_pts = legend.segment_text_location_2d(vw, vh)
cent_txt = False if l_par.vertical else True
draw_2d_text = [
(txt, black(), rg.Point2d(loc.x, loc.y), cent_txt, _height, _font)
for txt, loc in zip(legend.segment_text, txt_pts)]
t_pt = legend.title_location_2d(vw, vh)
legend_title = (legend.title, black(), rg.Point2d(t_pt.x, t_pt.y),
False, _height, _font)
draw_2d_text.insert(0, legend_title)
return draw_sprite, draw_2d_text
[docs]
def ToString(self):
"""Overwrite .NET ToString method."""
return 'VisualizationSet Converter'
[docs]
class RhinoPointConduit(rd.DisplayConduit):
"""An optimized class to preview Rhino Point3d in the Rhino Display pipeline.
Args:
points: A list of Rhino Point3d to be displayed in the pipeline.
"""
def __init__(self, points):
"""Initialize RhinoPointConduit."""
self.draw_point_args = []
col = black()
for pt in points:
self.draw_point_args.append((pt, rd.PointStyle.RoundSimple, 5, col))
self.bbox = rg.BoundingBox(points)
[docs]
def CalculateBoundingBox(self, calculateBoundingBoxEventArgs):
"""Overwrite the method that passes the bounding box to the display."""
calculateBoundingBoxEventArgs.IncludeBoundingBox(self.bbox)
[docs]
def PostDrawObjects(self, drawEventArgs):
"""Overwrite the method that draws the objects in the display."""
# get the DisplayPipeline from the event arguments
display = drawEventArgs.Display
# for each object to be rendered, pass the drawing arguments
for draw_args in self.draw_point_args:
display.DrawPoint(*draw_args)