def findNeighbors(_srfcList): """ Takes in a list of surfaces. tests against others in the set to see if they are touching. Adds a 'Neighbor' marker if so""" for i, srfc in enumerate(_srfcList): for k in range(0, len(_srfcList)): #print 'Surface: {} looking at Surface: {}...'.format(i, k) vertsI = ghc.DeconstructBrep(_srfcList[i].Surface).vertices vertsK = ghc.DeconstructBrep(_srfcList[k].Surface).vertices if ghc.BrepXBrep(_srfcList[i].Surface, _srfcList[k].Surface).curves: if _srfcList[i].Neighbors != None: matchSetID = _srfcList[i].Neighbors elif _srfcList[k].Neighbors != None: matchSetID = _srfcList[k].Neighbors else: matchSetID = i _srfcList[i].addNeighbor(matchSetID) #branch[k].ID) _srfcList[k].addNeighbor(matchSetID) #branch[i].ID) return _srfcList
def brep_polyloops(brep): """ Returns the polyloop of all faces for a brep""" faces = ghc.DeconstructBrep(brep)[0] polyloops = [] for face in faces: edges = ghc.DeconstructBrep(face)[1] polyline = ghc.JoinCurves(edges, False) vertices = ghc.Explode(polyline, recursive=True)[1] polyloops.append(vertices) return polyloops
def cleanSrfcInput(_srfcsInput): """If Brep or Polysrfc are input, explode them""" outputSrfcs = [] with idf2ph_rhDoc(): for inputObj in _srfcsInput: if isinstance(rs.coercesurface(inputObj), Rhino.Geometry.BrepFace): # Catches Bare surfaces outputSrfcs.append(inputObj) elif isinstance(rs.coercebrep(inputObj), Rhino.Geometry.Brep): # Catches Polysurfaces / Extrusions or other Masses faces = ghc.DeconstructBrep(rs.coercebrep(inputObj)).faces if isinstance(faces, list): for face in faces: outputSrfcs.append(face) elif isinstance(rs.coercegeometry(inputObj), Rhino.Geometry.PolylineCurve): # Catches PolylineCurves if not rs.coercegeometry(inputObj).IsClosed: warn = 'Non-Closed Polyline Curves found. Make sure all curves are closed.' ghenv.Component.AddRuntimeMessage( ghK.GH_RuntimeMessageLevel.Remark, warn) else: faces = ghc.DeconstructBrep( rs.coercegeometry(inputObj)).faces if isinstance(faces, list): for face in faces: outputSrfcs.append(face) else: outputSrfcs.append(faces) return outputSrfcs
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 _get_edges_in_order(self, analysis_surface=None): """Sort the surface edges using the Degree about center as the Key Ordering yields edges in the order Bottom / Left / Top / Right repackege them unto L/R/B/T for output Arguments: analysis_surface (Brep): A rectangular Rino surface to perform the analysis on """ if not analysis_surface: analysis_surface = self.rh_surface srfcPlane = self._get_plane_aligned_to_surface( analysis_surface ) vectorList = self._get_vector_from_center_to_edge( analysis_surface, srfcPlane) edgeAngleDegrees = self._calc_edge_angle_about_center(vectorList) srfcEdges_Unordered = ghc.DeconstructBrep(analysis_surface).edges srfcEdges_Ordered = ghc.SortList( edgeAngleDegrees, srfcEdges_Unordered).values_a # Convert all the Rhino lines to Ladybug LineSegments before output _bottom, _left, _top, _right = srfcEdges_Ordered _left = self._my_lb_line_constructor(_left) _right = self._my_lb_line_constructor(_right) _bottom = self._my_lb_line_constructor(_bottom) _top = self._my_lb_line_constructor(_top) output = self.Output(_left, _right, _bottom, _top) return output
def _get_verts(obj): brp_edges = ghc.DeconstructBrep(obj).edges brp_perim = ghc.JoinCurves(brp_edges, True) brp_verts = ghc.ControlPoints(brp_perim).points brpC = ghc.CullDuplicates(brp_verts, 0.0).points verts = (ev.from_Rh_points(vert) for vert in brpC) #brp_verts return list(verts)
def _get_vertsFloor(obj): #brp_edges = ghc.DeconstructBrep(obj).edges #brp_perim = ghc.JoinCurves(brp_edges, True) #brp_verts = ghc.ControlPoints(brp_perim).points #brpC = ghc.CullDuplicates(brp_verts, 0.0).points brp = ghc.DeconstructBrep(obj).vertices #brpC = ghc.ReverseList(brp) verts = [ev.from_Rh_points(point) for point in brp] return verts
def get_footprint(_surfaces): # Finds the 'footprint' of the building for 'Primary Energy Renewable' reference # 1) Re-build the Opaque Surfaces # 2) Join all the surface Breps into a single brep # 3) Find the 'box' for the single joined brep # 4) Find the lowest Z points on the box, offset another 10 units 'down' # 5) Make a new Plane at this new location # 6) Projects the brep edges onto the new Plane # 7) Split a surface using the edges, combine back into a single surface Footprint = namedtuple('Footprint', ['Footprint_surface', 'Footprint_area']) #----- Build brep surfaces = (from_face3d(surface.Srfc) for surface in _surfaces) bldg_mass = ghc.BrepJoin(surfaces).breps bldg_mass = ghc.BoundaryVolume(bldg_mass) if not bldg_mass: return Footprint(None, None) #------- Find Corners, Find 'bottom' (lowest Z) bldg_mass_corners = [v for v in ghc.BoxCorners(bldg_mass)] bldg_mass_corners.sort(reverse=False, key=lambda point3D: point3D.Z) rect_pts = bldg_mass_corners[0:3] #------- Projection Plane projection_plane1 = ghc.Plane3Pt(rect_pts[0], rect_pts[1], rect_pts[2]) projection_plane2 = ghc.Move(projection_plane1, ghc.UnitZ(-10)).geometry matrix = rs.XformPlanarProjection(projection_plane2) #------- Project Edges onto Projection Plane projected_edges = [] for edge in ghc.DeconstructBrep(bldg_mass).edges: projected_edges.append(ghc.Transform(edge, matrix)) #------- Split the projection surface using the curves l1 = ghc.Line(rect_pts[0], rect_pts[1]) l2 = ghc.Line(rect_pts[0], rect_pts[2]) max_length = max(ghc.Length(l1), ghc.Length(l2)) projection_surface = ghc.Polygon(projection_plane2, max_length * 100, 4, 0).polygon projected_surfaces = ghc.SurfaceSplit(projection_surface, projected_edges) #------- Remove the biggest surface from the set(the background srfc) projected_surfaces.sort(key=lambda x: x.GetArea()) projected_surfaces.pop(-1) #------- Join the new srfcs back together into a single one unioned_NURB = ghc.RegionUnion(projected_surfaces) unioned_surface = ghc.BoundarySurfaces(unioned_NURB) return Footprint(unioned_surface, unioned_surface.GetArea())
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 _get_vector_from_center_to_edge(_surface, _surface_plane): """ Find a Vector from center of surface to mid-point on each edge. Arguments: _surface: The Rhino surface to analyze. _surface_plane: A Plane aligned to the surface. Returns: edgeVectors: (List) Vector3D for mid-point on each edge """ worldOrigin = Rhino.Geometry.Point3d(0,0,0) worldXYPlane = ghc.XYPlane(worldOrigin) geomAtWorldZero = ghc.Orient(_surface, _surface_plane, worldXYPlane).geometry edges = ghc.DeconstructBrep(geomAtWorldZero).edges # Find the mid-point for each edge and create a vector to that midpoint crvMidPoints = [ ghc.CurveMiddle(edge) for edge in edges ] edgeVectors = [ ghc.Vector2Pt(midPt, worldOrigin, False).vector for midPt in crvMidPoints ] return edgeVectors
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
curve_point, _ = ghc.Move(curve_point, normal[0] * distance) points.append(curve_point) return points else: segment.Domain = reparam normal = ghc.CrossProduct(tangents, global_Z, True) curve_point = ghc.EvaluateCurve(segment, 0.5)[0] curve_point, _ = ghc.Move(curve_point, normal[0][0] * distance) return [curve_point] # Standardize surfaces rooms = [standardize_surfaces(room) for room in rooms] # Convert brep to polylines room_segments = [ghc.DeconstructBrep(room)[1] for room in rooms] room_polylines = [ghc.JoinCurves(segments, True) for segments in room_segments] # Main script for i, room_polyline in enumerate(room_polylines): connect = set() for segment in room_segments[i]: points = create_outside_points(segment) P.append(points) if type(points) in [list, tuple]: for p in points: for j, pl in enumerate(room_polylines): if j not in connect: relation, _ = ghc.PointInCurve(p, pl) if relation > 0: connect.add(j)
def set_perim_edge_values(self, _crv_guids, _ud_psi): """Pulls Rhino Scene parameters for a list of Curve Objects Takes in a list of curve GUIDs and goes to Rhino. Looks in their UserText to get any user applied parameter data. Calculates the sum of all curve lengths (m) in the list, as well as the total Psi-Value * Length (W/m) of all curves in the list. Will return tuple(0, 0) on any trouble getting parameter values or any fails Args: self: _perimCrvs (list): A list of Curve GUIDs to look at in the Rhino Scene Returns: totalLen, psiXlen (tuple): The total length of all curves in the list (m) and the total Psi*Len value (W/m) """ def _getLengthIfNumber(_in, _psi): try: length = float(_in) except: length = None try: psi = float(_psi) except: psi = self.default_perim_psi return length, psi if _crv_guids == None: return None if len(_crv_guids) == 0: return None psiXlen = 0 totalLen = 0 for crvGUID in _crv_guids: # See if its just Numbers passed in. If so, use them and break out length, crvPsiValue = _getLengthIfNumber(crvGUID, _ud_psi) if length and crvPsiValue: totalLen += length psiXlen += (length * crvPsiValue) continue isCrvGeom = rs.coercecurve(crvGUID) isBrepGeom = rs.coercebrep(crvGUID) if isCrvGeom: crvLen = ghc.Length(isCrvGeom) try: crvPsiValue = float(_ud_psi) except: crvPsiValue, warning = self._get_curve_psi_value(crvGUID) totalLen += crvLen psiXlen += (crvLen * crvPsiValue) elif isBrepGeom: srfcEdges = ghc.DeconstructBrep(isBrepGeom).edges srfcPerim = ghc.JoinCurves(srfcEdges, False) crvLen = ghc.Length(srfcPerim) try: crvPsiValue = float(_ud_psi) except: crvPsiValue = self.default_perim_psi # Default 0.05 W/mk warning = 'Note: You passed in a surface without any Psi-Values applied.\n'\ 'I will apply a default {} W/mk Psi-Value to ALL the edges of the\n'\ 'surface passed in.'.format( self.default_perim_psi ) self.ghenv.Component.AddRuntimeMessage( ghK.GH_RuntimeMessageLevel.Warning, warning) totalLen += crvLen psiXlen += (crvLen * crvPsiValue) else: warning = 'Error in GROUND: Input into _exposedPerimCrvs is not a Curve or Surface?\n'\ 'Please ensure inputs are Curve / Polyline or Surface only.' self.ghenv.Component.AddRuntimeMessage( ghK.GH_RuntimeMessageLevel.Warning, warning) self.perim_len = totalLen self.perim_psi_X_len = psiXlen