def _inset_floor_surfaces( _floor_surface, _inset_dist, _ghenv ): '''Shrinks/Insets the surface by the specified amount ''' try: rh_srfc = from_face3d(_floor_surface.geometry) except Exception as e: msg = 'Error. Can not convert floor surface: "{}" to Rhino geometry?'.format( _floor_surface ) _ghenv.Component.AddRuntimeMessage(ghK.GH_RuntimeMessageLevel.Remark, msg) return None if _inset_dist < 0.001: return rh_srfc #----------------------------------------------------------------------- srfcPerim = ghc.JoinCurves( ghc.BrepEdges(rh_srfc)[0], preserve=False ) # Get the inset Curve srfcCentroid = Rhino.Geometry.AreaMassProperties.Compute(rh_srfc).Centroid plane = ghc.XYPlane(srfcCentroid) srfcPerim_Inset_Pos = ghc.OffsetCurve(srfcPerim, _inset_dist, plane, 1) srfcPerim_Inset_Neg = ghc.OffsetCurve(srfcPerim, _inset_dist*-1, srfcCentroid, 1) # Choose the right Offset Curve. The one with the smaller area srfcInset_Pos = ghc.BoundarySurfaces( srfcPerim_Inset_Pos ) srfcInset_Neg = ghc.BoundarySurfaces( srfcPerim_Inset_Neg ) area_Pos = ghc.Area(srfcInset_Pos).area area_neg = ghc.Area(srfcInset_Neg).area if area_Pos < area_neg: return srfcInset_Pos else: return srfcInset_Neg
def depth(self): '''Used for non-res lighting evaluation. The room depth(m) from the main window wall ''' if self._depth: return self._depth worldXplane = ghc.XYPlane( Rhino.Geometry.Point3d(0,0,0) ) # Find the 'short' edge and the 'long' egde of the srfc geometry srfcEdges = ghc.DeconstructBrep(self.surface).edges segLengths = ghc.SegmentLengths(srfcEdges).longest_length srfcEdges_sorted = ghc.SortList(segLengths, srfcEdges).values_a endPoints = ghc.EndPoints(srfcEdges_sorted[-1]) longEdgeVector = ghc.Vector2Pt(endPoints.start, endPoints.end, False).vector shortEdgeVector = ghc.Rotate(longEdgeVector, ghc.Radians(90), worldXplane).geometry # Use the edges to find the orientation and dimensions of the room srfcAligedPlane = ghc.ConstructPlane(ghc.Area(self.surface).centroid, longEdgeVector, shortEdgeVector) srfcAlignedWorld = ghc.Orient(self.surface, srfcAligedPlane, worldXplane).geometry dims = ghc.BoxProperties( srfcAlignedWorld ).diagonal dims = [dims.X, dims.Y] width = min(dims) depth = max(dims) return depth
def _getheight(obj): geomlist = [x for n in obj for x in n] te = ghc.BrepJoin(geomlist).breps sm = ghc.MergeFaces(te).breps pt = ghc.Area(sm).centroid return pt.Z
def _get_plane_aligned_to_surface(_surface): """Finds an Aligned Plane for Surface input Note, will try and correct to make sure the aligned plane's Y-Axis aligns to the surface and goes 'up' (world Z) if it can. Arguments: _surface: The Rhino surface to align with Returns: srfcPlane: A single Plane object, aligned to the surface """ # Get the UV info for the surface srfcPlane = rs.SurfaceFrame(_surface, [0.5, 0.5]) centroid = ghc.Area(_surface).centroid uVector = srfcPlane.XAxis vVector = srfcPlane.YAxis # Create a Plane aligned to the UV of the srfc lineU = ghc.LineSDL(centroid, uVector, 1) lineV = ghc.LineSDL(centroid, vVector, 1) srfcPlane = ghc.Line_Line(lineU, lineV) # Try and make sure its pointing the right directions if abs(round(srfcPlane.XAxis.Z, 2)) != 0: srfcPlane = ghc.RotatePlane(srfcPlane, ghc.Radians(90)) if round(srfcPlane.YAxis.Z, 2) < 0: srfcPlane = ghc.RotatePlane(srfcPlane, ghc.Radians(180)) return srfcPlane
def getGHSrfNormal(GHSrf): centroid = ghc.Area(GHSrf).centroid normalVector = ghc.EvaluateSurface(GHSrf, centroid).normal return normalVector, GHSrf
def getWindowBasics(_in): with idf2ph_rhDoc(): # Get the Window Geometry geom = rs.coercegeometry(_in) windowSurface = ghc.BoundarySurfaces(geom) # Inset the window just slightly. If any windows touch one another or the zone edges # will failt to create a proper closed Brep. So shink them ever so slightly. Hopefully # not enough to affect the results. windowPerim = ghc.JoinCurves(ghc.DeconstructBrep(windowSurface).edges, preserve=False) try: windowPerim = ghc.OffsetonSrf( windowPerim, 0.004, windowSurface) # 0.4mm so hopefully rounds down except: windowPerim = ghc.OffsetonSrf(windowPerim, -0.004, windowSurface) windowSurface = ghc.BoundarySurfaces(windowPerim) # Pull in the Object Name from Rhino Scene windowName = None try: windowName = rs.ObjectName(_in) except: warning = "Can't get the Window name from Rhino for some reason?\n"\ "If you are passing in Rhino Geometry, double check you have named all the surfaces?\n"\ "If you are passing in Grasshopper geometry though, ignore this message." ghenv.Component.AddRuntimeMessage( ghK.GH_RuntimeMessageLevel.Remark, warning) windowName = windowName if windowName != None else 'Unnamed_Window' windowName = cleanUpName(windowName) # Double check that the surface Normal didn't get flipped c1 = ghc.Area(geom).centroid n1 = rs.SurfaceNormal(geom, c1) c2 = ghc.Area(windowSurface).centroid n2 = rs.SurfaceNormal(windowSurface, c2) normAngleDifference = ghc.Degrees(ghc.Angle(n1, n2).angle) if round(normAngleDifference, 0) != 0: # Flip the surface if it doesn't match the source windowSurface = ghc.Flip(windowSurface).surface return windowName, windowSurface
def roomCenterPt(_srfcs): srfcCenters = [] for eachSrfc in _srfcs: srfcCenters.append(ghc.Area(eachSrfc).centroid) roomCenter = ghc.Average(srfcCenters) return roomCenter
def set_surface_values(self, _srfc_guids): """Pulls Rhino Scene parameters for a list of Surface Object Guids Takes in a list of surface GUIDs and goes to Rhino. Looks in their UserText to get any user applied parameter data. Will also find the surface area of each surface in the list. Calculates the total surface area of all surfaces in the list, as well as the area-weighted U-Value of the total. Will return tuple(0, 0) on any trouble getting parameter values or any fails Args: self: _flrSrfcs (list): A list of Surface GUIDs to look at in the Rhino Scene Returns: totalFloorArea, floorUValue (tuple): The total floor area (m2) and the area weighted U-Value """ if _srfc_guids == None: return 0, 0 if len(_srfc_guids) > 0: floorAreas = [] weightedUvales = [] for srfcGUID in _srfc_guids: # Get the Surface Area Params srfcGeom = rs.coercebrep(srfcGUID) if srfcGeom: srfcArea = ghc.Area(srfcGeom).area floorAreas.append(srfcArea) # Get the Surface U-Values Params srfcUvalue = self._get_surface_U_value(srfcGUID) weightedUvales.append(srfcUvalue * srfcArea) else: floorAreas.append(1) weightedUvales.append(1) warning = 'Error: Input into _floor_surfaces is not a Surface?\n'\ 'Please ensure inputs are Surface Breps only.' self.ghenv.Component.AddRuntimeMessage( ghK.GH_RuntimeMessageLevel.Warning, warning) totalFloorArea = sum(floorAreas) floorUValue = sum(weightedUvales) / totalFloorArea else: totalFloorArea = 0 floorUValue = 0 self.floor_area = totalFloorArea self.floor_U_value = floorUValue
def inset_rhino_surface(_srfc, _inset_dist=0.001, _srfc_name=""): """ Insets/shrinks a Rhino Brep some dimension Arg: _srfc: A Rhino Brep _inset_dist: float: Default=0.001m _srfc_name: str: The name of the surface, used for error messages Returns: new_srfc: A new Rhino surface, shrunk/inset by the specified amount """ #----------------------------------------------------------------------- # Get all the surface params needed srfc_Center = ghc.Area(_srfc).centroid srfc_normal_vector = brep_avg_surface_normal(_srfc) srfc_edges = ghc.DeconstructBrep(_srfc).edges srfc_perimeter = ghc.JoinCurves(srfc_edges, False) #----------------------------------------------------------------------- # Try to inset the perimeter Curve inset_curve = rs.OffsetCurve(srfc_perimeter, srfc_Center, _inset_dist, srfc_normal_vector, 0) #----------------------------------------------------------------------- # In case the new curve goes 'out' and the offset fails # Or is too small and results in multiple offset Curves if len(inset_curve)>1: warning = 'Error. The surface: "{}" is too small. The offset of {} m"\ "can not be done. Check the offset size?'.format(_srfc_name, _inset_dist) print(warning) inset_curve = rs.OffsetCurve(srfc_perimeter, srfc_Center, 0.001, srfc_normal_vector, 0) inset_curve = rs.coercecurve( inset_curve[0] ) else: inset_curve = rs.coercecurve( inset_curve[0] ) new_srfc = ghc.BoundarySurfaces(inset_curve) return new_srfc
def center_point(self): cps = [ ghc.Area(tfa_srfc).centroid for tfa_srfc in self.space_tfa_surfaces ] cp = ghc.Average(cps) return rs.CreatePoint(*cp)
def _getz(obj): geomlst = [x for n in obj for x in n] te = ghc.BrepJoin(geomlst).breps cnt = ghc.Area(te).centroid return cnt.Z
def get_surface_area(_srfc): return ghc.Area(_srfc.geometry)[0]
def find_reveal_shading(_phpp_window_obj, _shadingGeom, _extents=99): WinCenter = ghc.Area(_phpp_window_obj.glazing_surface).centroid edges = _phpp_window_obj._get_edges_in_order( _phpp_window_obj.glazing_surface ) surface_normal = _phpp_window_obj.surface_normal #Create the Intersection Surface for each side Side1_OriginPt = ghc.CurveMiddle( from_linesegment3d(edges.Left) ) Side1_NormalLine = ghc.LineSDL(Side1_OriginPt, surface_normal, _extents) Side1_Direction = ghc.Vector2Pt(WinCenter, Side1_OriginPt, False).vector Side1_HorizLine = ghc.LineSDL(Side1_OriginPt, Side1_Direction, _extents) Side1_IntersectionSurface = ghc.SumSurface(Side1_NormalLine, Side1_HorizLine) #Side2_OriginPt = SideMidPoints[1] #ghc.CurveMiddle(self.Edge_Left) Side2_OriginPt = ghc.CurveMiddle( from_linesegment3d(edges.Right) ) Side2_NormalLine = ghc.LineSDL(Side2_OriginPt, surface_normal, _extents) Side2_Direction = ghc.Vector2Pt(WinCenter, Side2_OriginPt, False).vector Side2_HorizLine = ghc.LineSDL(Side2_OriginPt, Side2_Direction, _extents) Side2_IntersectionSurface = ghc.SumSurface(Side2_NormalLine, Side2_HorizLine) #Find any Shader Objects and put them all into a list Side1_RevealShaderObjs = [] testStartPt = ghc.Move(WinCenter, ghc.Amplitude(surface_normal, 0.1)).geometry #Offsets the test line just a bit Side1_TesterLine = ghc.LineSDL(testStartPt, Side1_Direction, _extents) #extend a line off to side 1 for i in range(len(_shadingGeom)): if ghc.BrepXCurve(_shadingGeom[i],Side1_TesterLine).points != None: Side1_RevealShaderObjs.append(_shadingGeom[i]) Side2_RevealShaderObjs = [] Side2_TesterLine = ghc.LineSDL(testStartPt, Side2_Direction, _extents) #extend a line off to side 2 for i in range(len(_shadingGeom)): if ghc.BrepXCurve(_shadingGeom[i],Side2_TesterLine).points != None: Side2_RevealShaderObjs.append(_shadingGeom[i]) #--------------------------------------------------------------------------- # Calc Shading reveal dims NumShadedSides = 0 if len(Side1_RevealShaderObjs) != 0: Side1_o_reveal = CalcRevealDims(_phpp_window_obj, Side1_RevealShaderObjs, Side1_IntersectionSurface, Side1_OriginPt, Side1_Direction)[0] Side1_d_reveal = CalcRevealDims(_phpp_window_obj, Side1_RevealShaderObjs, Side1_IntersectionSurface, Side1_OriginPt, Side1_Direction)[1] Side1_CheckLine = CalcRevealDims(_phpp_window_obj, Side1_RevealShaderObjs, Side1_IntersectionSurface, Side1_OriginPt, Side1_Direction)[2] NumShadedSides = NumShadedSides + 1 else: Side1_o_reveal = None Side1_d_reveal = None Side1_CheckLine = Side1_HorizLine if len(Side2_RevealShaderObjs) != 0: Side2_o_reveal = CalcRevealDims(_phpp_window_obj, Side2_RevealShaderObjs, Side2_IntersectionSurface, Side2_OriginPt, Side2_Direction)[0] Side2_d_reveal = CalcRevealDims(_phpp_window_obj, Side2_RevealShaderObjs, Side2_IntersectionSurface, Side2_OriginPt, Side2_Direction)[1] Side2_CheckLine = CalcRevealDims(_phpp_window_obj, Side2_RevealShaderObjs, Side2_IntersectionSurface, Side2_OriginPt, Side2_Direction)[2] NumShadedSides = NumShadedSides + 1 else: Side2_o_reveal = None Side2_d_reveal = None Side2_CheckLine = Side2_HorizLine # # # # TODO: how to handel asymetrical reveals???? o_reveal = Side1_o_reveal#(Side1_o_reveal + Side2_o_reveal )/ max(1,NumShadedSides) d_reveal = Side1_d_reveal#(Side1_d_reveal + Side2_d_reveal )/ max(1,NumShadedSides) # # # # # return o_reveal, d_reveal, Side1_CheckLine, Side2_CheckLine
def find_overhang_shading(_phpp_window_obj, _shadingGeom, _extents=99): # Figure out the glass surface (inset a bit) and then # find the origin point for all the subsequent shading calcs (top, middle) glzgCenter = ghc.Area(_phpp_window_obj.glazing_surface).centroid glazingEdges = _phpp_window_obj._get_edges_in_order( _phpp_window_obj.glazing_surface ) glazingTopEdge = from_linesegment3d(glazingEdges.Top) ShadingOrigin = ghc.CurveMiddle(glazingTopEdge) # In order to also work for windows which are not vertical, find the # 'direction' from the glazing origin and the top/middle ege point UpVector = ghc.Vector2Pt(glzgCenter, ShadingOrigin, True).vector #----------------------------------------------------------------------- # First, need to filter the scene to find the objects that are 'above' # the window. Create a 'test plane' that is _extents (99m) tall and 0.5m past the wall surface, test if # any objects intersect that plane. If so, add them to the set of things # test in the next step depth = float(_phpp_window_obj.install_depth) + 0.5 edge1 = ghc.LineSDL(ShadingOrigin, UpVector, _extents) edge2 = ghc.LineSDL(ShadingOrigin, _phpp_window_obj.surface_normal, depth) intersectionTestPlane = ghc.SumSurface(edge1, edge2) OverhangShadingObjs = (x for x in _shadingGeom if ghc.BrepXBrep(intersectionTestPlane, x).curves != None) #----------------------------------------------------------------------- # Using the filtered set of shading objects, find the 'edges' of shading # geom and then decide where the maximums shading point is # Create a new 'test' plane coming off the origin (99m in both directions this time). # Test to find any intersection shading objs and all their crvs/points with this plane HorizontalLine = ghc.LineSDL(ShadingOrigin, _phpp_window_obj.surface_normal, _extents) VerticalLine = ghc.LineSDL(ShadingOrigin, UpVector, _extents) IntersectionSurface = ghc.SumSurface(HorizontalLine, VerticalLine) IntersectionCurves = (ghc.BrepXBrep(obj, IntersectionSurface).curves for obj in OverhangShadingObjs if ghc.BrepXBrep(obj, IntersectionSurface).curves != None) IntersectionPointsList = (ghc.ControlPoints(crv).points for crv in IntersectionCurves) IntersectionPoints = (pt for list_of_pts in IntersectionPointsList for pt in list_of_pts) #----------------------------------------------------------------------- # If there are any intersection Points found, choose the right one to use to calc shading.... # Find the top/closets point for each of the objects that could possibly shade smallest_angle_found = 2 * math.pi key_point = None for pt in IntersectionPoints: if pt == None: continue # Protect against Zero-Length error ray = ghc.Vector2Pt(ShadingOrigin, pt, False).vector if ray.Length < 0.001: continue this_ray_angle = ghc.Angle(_phpp_window_obj.surface_normal , ray).angle if this_ray_angle < 0.001: continue if this_ray_angle <= smallest_angle_found: smallest_angle_found = this_ray_angle key_point = pt #----------------------------------------------------------------------- # Use the 'key point' found to deliver the Height and Distance for the PHPP Shading Calculator if not key_point: d_over = None o_over = None CheckLine = VerticalLine else: d_over = key_point.Z - ShadingOrigin.Z # Vertical distance Hypot = ghc.Length(ghc.Line(ShadingOrigin, key_point)) # Hypot o_over = math.sqrt(Hypot**2 - d_over**2) # Horizontal distance CheckLine = ghc.Line(ShadingOrigin, key_point) return d_over, o_over, CheckLine
def brep_area(brep, plane): """ Computes plane area of a brep""" section_curve = ghc.BrepXPlane(brep,plane)[0] area = ghc.Area(section_curve)[0] return area