Source code for ladybug_rhino.planarize
"""Functions to convert curved Rhino geometries into planar ladybug ones."""
from .config import tolerance
try:
from ladybug_geometry.geometry3d.pointvector import Point3D
from ladybug_geometry.geometry3d.face import Face3D
except ImportError as e:
raise ImportError("Failed to import ladybug_geometry.\n{}".format(e))
try:
import Rhino.Geometry as rg
except ImportError as e:
raise ImportError(
"Failed to import Rhino.\n{}".format(e))
import sys
if (sys.version_info > (3, 0)): # python 3
xrange = range
"""____________INDIVIDUAL SURFACES TO PLANAR____________"""
[docs]
def planar_face_curved_edge_vertices(b_face, count, meshing_parameters):
"""Extract vertices from a planar brep face loop that has one or more curved edges.
This method ensures vertices along the curved edge are generated in a way that
they align with an extrusion of that edge. Alignment may not be possible when
the adjoining curved surface is not an extrusion.
Args:
b_face: A brep face with the curved edge.
count: An integer for the index of the loop to extract.
meshing_parameters: Rhino Meshing Parameters to describe how
curved edge should be converted into planar elements.
Returns:
A list of ladybug Point3D objects representing the input planar face.
"""
loop_pcrv = b_face.Loops.Item[count].To3dCurve()
f_norm = b_face.NormalAt(0, 0)
if f_norm.Z < 0:
loop_pcrv.Reverse()
loop_verts = []
try:
loop_pcrvs = [loop_pcrv.SegmentCurve(i)
for i in xrange(loop_pcrv.SegmentCount)]
except Exception:
try:
loop_pcrvs = [loop_pcrv[0]]
except Exception:
loop_pcrvs = [loop_pcrv]
for seg in loop_pcrvs:
if seg.Degree == 1:
loop_verts.append(_point3d(seg.PointAtStart))
else:
# Ensure curve subdivisions align with adjacent curved faces
seg_mesh = rg.Mesh.CreateFromSurface(
rg.Surface.CreateExtrusion(seg, f_norm),
meshing_parameters)
for i in xrange(seg_mesh.Vertices.Count / 2 - 1):
loop_verts.append(_point3d(seg_mesh.Vertices[i]))
return loop_verts
[docs]
def curved_surface_faces(b_face, meshing_parameters):
"""Extract Face3D objects from a curved brep face.
Args:
b_face: A curved brep face.
meshing_parameters: Rhino Meshing Parameters to describe how
curved edge should be converted into planar elements.
Returns:
A list of ladybug Face3D objects that together approximate the input
curved surface.
"""
if b_face.OrientationIsReversed:
b_face.Reverse(0, True)
face_brep = b_face.DuplicateFace(True)
meshed_brep = rg.Mesh.CreateFromBrep(face_brep, meshing_parameters)[0]
return mesh_faces_to_face3d(meshed_brep)
"""____________SOLID BREPS TO PLANAR____________"""
[docs]
def curved_solid_faces(brep, meshing_parameters, ignore_sliver=True):
"""Extract Face3D objects from a curved solid brep.
This method ensures that the resulting Face3Ds sill form a closed solid if
the input brep is closed. This is accomplished by meshing the solid Brep
altogether.
Args:
brep: A curved solid brep.
meshing_parameters: Rhino Meshing Parameters to describe how curved surfaces
should be converted into planar elements. If None, Rhino's Default
Meshing Parameters will be used.
ignore_sliver: A Boolean to note whether tiny sliver faces should simply be
excluded from the output (True) or whether a None should be put in
their place (False). The latter is useful when reporting to the user
that certain tiny geometries interfered with the planarization
process and the Rhino model tolerance should probably be lowered
in order to get a better planar representation. (Default: True).
Returns:
A list of ladybug Face3D objects that together approximate the input brep.
"""
# mesh the geometry as a solid
mesh_par = meshing_parameters or rg.MeshingParameters.Default # default
meshed_geo = rg.Mesh.CreateFromBrep(brep, mesh_par)
# evaluate each mesh face to see what larger brep face it is a part of
faces = []
for mesh, b_face in zip(meshed_geo, brep.Faces):
if b_face.IsPlanar(tolerance): # only take the naked vertices of planar faces
naked_edges = mesh.GetNakedEdges()
all_verts = []
for loop_pline in naked_edges: # each loop_pline is a boundary/hole
all_verts.append([_point3d(loop_pline.Item[i])
for i in xrange(loop_pline.Count - 1)])
if len(all_verts) == 1: # No holes in the shape
faces.append(Face3D(all_verts[0]))
else: # There's at least one hole in the shape
faces.append(
Face3D(boundary=all_verts[0], holes=all_verts[1:]))
else:
faces.extend(mesh_faces_to_face3d(mesh))
# remove colinear vertices as the meshing process makes a lot of them
final_faces = []
for face in faces:
try:
final_faces.append(face.remove_colinear_vertices(tolerance))
except AssertionError: # tiny sliver Face that should not be included
if not ignore_sliver:
final_faces.append(None)
return final_faces
"""________________EXTRA HELPER FUNCTIONS________________"""
[docs]
def has_curved_face(brep):
"""Test if a Rhino Brep has a curved face.
Args:
brep: A Rhino Brep to test whether it has a curved face.
"""
for b_face in brep.Faces:
if not b_face.IsPlanar(tolerance):
return True
return False
[docs]
def mesh_faces_to_face3d(mesh):
"""Convert a curved Rhino mesh faces into planar ladybug_geometry Face3D.
Args:
mesh: A curved Rhino mesh.
Returns:
A list of ladybug Face3D objects derived from the input mesh faces.
"""
faces = []
for m_face in mesh.Faces:
if m_face.IsQuad:
lb_face = Face3D(
tuple(_point3d(mesh.Vertices[i]) for i in
(m_face.A, m_face.B, m_face.C, m_face.D)))
if lb_face.check_planar(tolerance, False):
faces.append(lb_face)
else:
lb_face_1 = Face3D(
tuple(_point3d(mesh.Vertices[i]) for i in
(m_face.A, m_face.B, m_face.C)))
lb_face_2 = Face3D(
tuple(_point3d(mesh.Vertices[i]) for i in
(m_face.C, m_face.D, m_face.A)))
faces.extend([lb_face_1, lb_face_2])
else:
lb_face = Face3D(
tuple(_point3d(mesh.Vertices[i]) for i in
(m_face.A, m_face.B, m_face.C)))
faces.append(lb_face)
return faces
def _point3d(point):
"""Ladybug Point3D from Rhino Point3d."""
return Point3D(point.X, point.Y, point.Z)