Skip to content

Commit

Permalink
fix(visualize_win_frames): Support Window Shade Construction
Browse files Browse the repository at this point in the history
- Update PH Frame visualizer to support WindowShadeConstructions
  • Loading branch information
ed-p-may committed Feb 27, 2024
1 parent f733f92 commit 62d3acd
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 39 deletions.
2 changes: 1 addition & 1 deletion honeybee_ph_rhino/_component_info_.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
These are called when the component is instantiated within the Grasshopper canvas.
"""

RELEASE_VERSION = "Honeybee-PH v1.2.05"
RELEASE_VERSION = "Honeybee-PH v1.2.06"
CATEGORY = "HB-PH"
SUB_CATEGORIES = {
0: "00 | Utils",
Expand Down
79 changes: 41 additions & 38 deletions honeybee_ph_rhino/gh_compo_io/visualize_win_frames.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import math

try:
from typing import Iterable, List, Tuple
from typing import Iterable, List, Tuple, Sequence
except ImportError:
pass

Expand All @@ -18,10 +18,10 @@
try:
from Grasshopper import DataTree # type: ignore
from Grasshopper.Kernel.Data import GH_Path # type: ignore
from Rhino.Geometry import (
from Rhino.Geometry import ( # type: ignore
Brep,
Interval,
LineCurve, # type: ignore
LineCurve,
Plane,
Point3d,
Vector3d,
Expand All @@ -30,31 +30,24 @@
except ImportError:
pass # Outside Rhino

try:
from ladybug_geometry.geometry3d import LineSegment3D
except ImportError as e:
raise ImportError("\nFailed to import ladybug_geometry:\n\t{}".format(e))

try:
from ladybug_rhino.fromgeometry import (
from_face3d,
from_linesegment3d,
from_plane,
from_point3d,
)
except ImportError as e:
raise ImportError("\nFailed to import ladybug_rhino:\n\t{}".format(e))

try:
from honeybee.aperture import Aperture
from honeybee_energy.construction.window import WindowConstruction
except ImportError as e:
raise ImportError("\nFailed to import honeybee:\n\t{}".format(e))

from honeybee_energy_ph.construction.window import PhWindowFrame, PhWindowFrameElement
from honeybee_energy_ph.properties.construction.window import (
WindowConstructionPhProperties,
)
try:
from honeybee_energy_ph.construction.window import PhWindowFrameElement
except ImportError as e:
raise ImportError("\nFailed to import honeybee_energy_ph:\n\t{}".format(e))

try:
from honeybee_ph_rhino import gh_io
Expand Down Expand Up @@ -82,10 +75,10 @@ def calc_edge_angle_about_origin(self, _edge, _center_pt, _pl, _tol=0.0001):

# -- Find the vector from the edge's midpoint to the center
edge_midpoint = self.get_edge_midpoint(_edge)
vec = edge_midpoint - _center_pt
vector_from_mid_to_center = Point3d.Subtract(edge_midpoint, _center_pt)

# -- Find the angle between the edge vector and the parent plane's local-Y axis
angle = math.degrees(Vector3d.VectorAngle(_pl.YAxis, vec, _pl))
angle = math.degrees(Vector3d.VectorAngle(_pl.YAxis, vector_from_mid_to_center, _pl))
angle = round(angle, 2)

# -- Ensure no floating-point errors
Expand All @@ -95,7 +88,7 @@ def calc_edge_angle_about_origin(self, _edge, _center_pt, _pl, _tol=0.0001):
return angle

def sort_aperture_edges(self, _ap_edges, _ap_center_point, _ap_local_plane):
# type: (List[LineCurve], Point3d, Plane) -> List[LineSegment3D]
# type: (Sequence[LineCurve], Point3d, Plane) -> List[LineCurve]
"""Sort the edges of the aperture based on their angle about the aperture's center point.
Note: the native Honeybee .get_left_right_edges methods don't seem to work properly?
Expand Down Expand Up @@ -123,31 +116,41 @@ def create_frame_surface(self, _ap_edges, _ap_frame_elements, ap_ctr_pt):

return frame_surfaces

def create_glazing_surface(self, _frame_surfaces, _ap_srfc, _ap_ctr_pt):
def create_glazing_surface(self, _frame_surfaces, _ap_surface, _ap_ctr_pt):
# type: (List[Brep], Brep, Point3d) -> Brep
"""Create the glazing surface for the aperture."""
joined_frames = self.IGH.ghc.BrepJoin(_frame_surfaces).breps
edges = self.IGH.ghc.DeconstructBrep(joined_frames).edges
win_srfcs = self.IGH.ghc.SurfaceSplit(_ap_srfc, edges)
win_surfaces = self.IGH.ghc.SurfaceSplit(_ap_surface, edges)

# -- Figure out which of the split surfaces is the glazing surface
# -- by choosing the surface with the closest point to the aperture's center point
ct_pt_distances = []
for test_srfc in win_srfcs:
for test_surface in win_surfaces:
ct_pt_distances.append(
self.IGH.ghc.SurfaceClosestPoint(_ap_ctr_pt, test_srfc).distance
self.IGH.ghc.SurfaceClosestPoint(_ap_ctr_pt, test_surface).distance
)
glazing_srfc = win_srfcs[ct_pt_distances.index(min(ct_pt_distances))]
glazing_surface = win_surfaces[ct_pt_distances.index(min(ct_pt_distances))]

return glazing_srfc
return glazing_surface

def get_aperture_ph_frame_elements(self, _aperture):
# type: (Aperture) -> Tuple[List[PhWindowFrameElement], List[str]]
"""Get the Passive House PhWindowFrameElements for of the aperture;s PH-Frame."""
ap_const = _aperture.properties.energy.construction # type: ignore
ap_prop_ph = ap_const.properties.ph # type: WindowConstructionPhProperties

# -- Find the HBPH-Properties for the Window Construction
try:
"""
If it's a Honeybee Energy WindowConstructionShade the actual
construction will be inside the 'window_construction' attribute
"""
ap_prop_ph = ap_const.window_construction.properties.ph
except AttributeError:
ap_prop_ph = ap_const.properties.ph

# -- Try and get the PH-Frame from the Window Construction
ap_ph_frame = ap_prop_ph.ph_frame

if not ap_ph_frame:
msg = "Error: The Aperture {} does not have a Passive House window frame?, skipping...".format(
_aperture.display_name
Expand All @@ -159,29 +162,29 @@ def get_aperture_ph_frame_elements(self, _aperture):
return ap_ph_frame.elements, el_names

def get_aperture_geometry(self, _aperture):
# type: (Aperture) -> tuple[Brep, Point3d, Plane, List[LineSegment3D]]
# type: (Aperture) -> tuple[Brep, Point3d, Plane, List[LineCurve]]
"""Get the geometric elements of the Honeybee-Aperture as Rhino Geometry."""
ap_srfc = from_face3d(_aperture.geometry)
ap_ctr_pt = self.IGH.ghc.Area(ap_srfc).centroid
ap_surface = from_face3d(_aperture.geometry) # type: Brep # type: ignore
ap_ctr_pt = self.IGH.ghc.Area(ap_surface).centroid
ap_local_plane = from_plane(_aperture.geometry.plane)
ap_edges = [from_linesegment3d(s) for s in _aperture.geometry.boundary_segments]
ap_edges_sorted = self.sort_aperture_edges(ap_edges, ap_ctr_pt, ap_local_plane)
return ap_srfc, ap_ctr_pt, ap_local_plane, ap_edges_sorted
return ap_surface, ap_ctr_pt, ap_local_plane, ap_edges_sorted

def run(self):
# type: () -> tuple[DataTree[Object], DataTree[Object], DataTree[str], DataTree[str], DataTree[str]]
"""Run the component."""
frame_srfcs_ = DataTree[Object]()
glazing_srfcs_ = DataTree[Object]()
frame_surfaces_ = DataTree[Object]()
glazing_surfaces_ = DataTree[Object]()
frame_element_type_names_ = DataTree[str]()
edges_ = DataTree[LineCurve]()
planes_ = DataTree[Plane]()

for i, ap in enumerate(self.apertures):
# -----------------------------------------------------------------------
# -- Pull out all the relevant Aperture data that is needed throughout
# -- Convert to from Ladubug to Rhino geometry for all the later operations.
srfc, ctr_pt, local_plane, edges = self.get_aperture_geometry(ap)
# -- Convert to from Ladybug to Rhino geometry for all the later operations.
surface, ctr_pt, local_plane, edges = self.get_aperture_geometry(ap)
hbph_frame_elements, element_names = self.get_aperture_ph_frame_elements(ap)

if not hbph_frame_elements:
Expand All @@ -190,12 +193,12 @@ def run(self):
# -----------------------------------------------------------------------
# -- Create all the Frame-Element Geometry
frame_surfaces = self.create_frame_surface(edges, hbph_frame_elements, ctr_pt)
frame_srfcs_.AddRange(frame_surfaces, GH_Path(i))
frame_surfaces_.AddRange(frame_surfaces, GH_Path(i))

# -----------------------------------------------------------------------
# -- Create the Glazing Geometry
glazing_srfc = self.create_glazing_surface(frame_surfaces, srfc, ctr_pt)
glazing_srfcs_.Add(glazing_srfc, GH_Path(i))
glazing_surface = self.create_glazing_surface(frame_surfaces, surface, ctr_pt)
glazing_surfaces_.Add(glazing_surface, GH_Path(i))

# -----------------------------------------------------------------------
# -- Get the other bits for debugging
Expand All @@ -204,8 +207,8 @@ def run(self):
planes_.Add(local_plane, GH_Path(i))

return (
frame_srfcs_,
glazing_srfcs_,
frame_surfaces_,
glazing_surfaces_,
frame_element_type_names_,
edges_,
planes_,
Expand Down

0 comments on commit 62d3acd

Please sign in to comment.