def surface_discrete_mapping(srf_guid, discretisation, minimum_discretisation = 5, crv_guids = [], pt_guids = []): """Map the boundaries of a Rhino NURBS surface to planar poylines dicretised within some discretisation using the surface UV parameterisation. Curve and point feautres on the surface can be included. Parameters ---------- srf_guid : guid A surface guid. crv_guids : list List of guids of curves on the surface. pt_guids : list List of guids of points on the surface. discretisation : float The discretisation of the surface boundaries. minimum_discretisation : int The minimum discretisation of the surface boundaries. Returns ------- tuple Tuple of the mapped objects: outer boundary, inner boundaries, polyline_features, point_features. """ srf = RhinoSurface.from_guid(srf_guid) # a boundary may be made of multiple boundary components and therefore checking for closeness and joining are necessary mapped_borders = [] for i in [1, 2]: mapped_border = [] for border_guid in srf.borders(type = i): points = [list(srf.point_xyz_to_uv(pt)) + [0.0] for pt in rs.DivideCurve(border_guid, max(int(rs.CurveLength(border_guid) / discretisation) + 1, minimum_discretisation))] if rs.IsCurveClosed(border_guid): points.append(points[0]) mapped_border.append(points) rs.DeleteObject(border_guid) mapped_borders.append(mapped_border) outer_boundaries, inner_boundaries = [network_polylines(Network.from_lines([(u, v) for border in mapped_borders[i] for u, v in pairwise(border)])) for i in [0, 1]] # mapping of the curve features on the surface mapped_curves = [] for crv_guid in crv_guids: curve = RhinoCurve.from_guid(crv_guid) points = [list(srf.point_xyz_to_uv(pt)) + [0.0] for pt in curve.divide(max(int(curve.length() / discretisation) + 1, minimum_discretisation))] if curve.is_closed(): points.append(points[0]) mapped_curves.append(points) polyline_features = network_polylines(Network.from_lines([(u, v) for curve in mapped_curves for u, v in pairwise(curve)])) # mapping of the point features onthe surface point_features = [list(srf.point_xyz_to_uv(rs.PointCoordinates(pt_guid))) + [0.0] for pt_guid in pt_guids] return outer_boundaries[0], inner_boundaries, polyline_features, point_features
def automated_smoothing_surface_constraints(mesh, surface): """Apply automatically surface-related constraints to the vertices of a mesh to smooth: kinks, boundaries and surface. Parameters ---------- mesh : Mesh The mesh to apply the constraints to for smoothing. surface : Rhino surface guid A Rhino surface guid on which to constrain mesh vertices. Returns ------- constraints : dict A dictionary of mesh constraints for smoothing as vertex keys pointing to point, curve or surface objects. """ surface = RhinoSurface.from_guid(surface) constraints = {} points = [rs.AddPoint(point) for point in surface.kinks()] curves = surface.borders(type = 0) constraints.update({vkey: surface.guid for vkey in mesh.vertices()}) for vkey in mesh.vertices_on_boundary(): xyz = mesh.vertex_coordinates(vkey) projections = {curve: distance_point_point(xyz, RhinoCurve.from_guid(curve).closest_point(xyz)) for curve in curves} constraints.update({vkey: min(projections, key = projections.get)}) key_to_index = {i: vkey for i, vkey in enumerate(mesh.vertices_on_boundary())} vertex_coordinates = tuple(mesh.vertex_coordinates(vkey) for vkey in mesh.vertices_on_boundary()) constraints.update({key_to_index[closest_point_in_cloud(rs.PointCoordinates(point), vertex_coordinates)[2]]: point for point in points}) return constraints
def automated_smoothing_constraints(mesh, points = None, curves = None, surface = None, mesh2 = None): """Apply automatically point, curve and surface constraints to the vertices of a mesh to smooth. Parameters ---------- mesh : Mesh The mesh to apply the constraints to for smoothing. points : list List of XYZ coordinates on which to constrain mesh vertices. Default is None. curves : list List of Rhino curve guids on which to constrain mesh vertices. Default is None. surface : Rhino surface guid A Rhino surface guid on which to constrain mesh vertices. Default is None. mesh2 : Rhino mesh guid A Rhino mesh guid on which to constrain mesh vertices. Default is None. Returns ------- constraints : dict A dictionary of mesh constraints for smoothing as vertex keys pointing to point, curve or surface objects. """ if surface: surface = RhinoSurface.from_guid(surface) if curves: curves = [RhinoCurve.from_guid(curve) for curve in curves] if mesh2: mesh2 = RhinoMesh.from_guid(mesh2) constraints = {} constrained_vertices = {} vertices = list(mesh.vertices()) vertex_coordinates = [mesh.vertex_coordinates(vkey) for vkey in mesh.vertices()] if points is not None and len(points) != 0: constrained_vertices.update({vertices[closest_point_in_cloud(rs.PointCoordinates(point), vertex_coordinates)[2]]: point for point in points}) if mesh2 is not None: constraints.update({vkey: mesh2.guid for vkey in mesh.vertices()}) if surface is not None: constraints.update({vkey: surface.guid for vkey in mesh.vertices()}) if curves is not None and len(curves) != 0: boundaries = [split_boundary for boundary in mesh.boundaries() for split_boundary in list_split(boundary, [boundary.index(vkey) for vkey in constrained_vertices.keys() if vkey in boundary])] boundary_midpoints = [Polyline([mesh.vertex_coordinates(vkey) for vkey in boundary]).point(t = .5) for boundary in boundaries] curve_midpoints = [rs.EvaluateCurve(curve, rs.CurveParameter(curve, .5)) for curve in curves] midpoint_map = {i: closest_point_in_cloud(boundary_midpoint, curve_midpoints)[2] for i, boundary_midpoint in enumerate(boundary_midpoints)} constraints.update({vkey: curves[midpoint_map[i]].guid for i, boundary in enumerate(boundaries) for vkey in boundary}) if points is not None: constraints.update(constrained_vertices) return constraints
def customized_smoothing_constraints(mesh, constraints): """Add custom point, curve and surface constraints to the vertices of a mesh to smooth. Parameters ---------- mesh : Mesh The mesh to apply the constraints to for smoothing. constraints : dict A dictionary of mesh constraints for smoothing as vertex keys pointing to point, curve or surface objects. Returns ------- constraints : dict The updated dictionary of mesh constraints for smoothing as vertex keys pointing to point, curve or surface objects. """ while True: guids = display_smoothing_constraints(mesh, constraints) vkeys = mesh_select_vertices(mesh) if len(vkeys) == 2 and rs.GetString( 'get all polyedge?', strings=['True', 'False']) == 'True': u, v = vkeys vkeys = mesh.polyedge(u, v) if vkeys is None: break constraint = rs.GetString( 'edit smoothing constraints?', strings=['point', 'curve', 'surface', 'exit']) rs.DeleteObjects(guids) if constraint is None or constraint == 'exit': break elif constraint == 'point': point = RhinoPoint.from_selection() constraints.update({vkey: point.guid for vkey in vkeys}) elif constraint == 'curve': curve = RhinoCurve.from_selection() constraints.update({vkey: curve.guid for vkey in vkeys}) elif constraint == 'surface': surface = RhinoSurface.from_selection() constraints.update({vkey: surface.guid for vkey in vkeys}) return constraints
def callback(k, args): mesh, constraints = args for vkey, constraint in constraints.items(): if constraint is None: continue elif rs.ObjectType(constraint) == 1: x, y, z = RhinoPoint.from_guid(constraint).xyz elif rs.ObjectType(constraint) == 4: x, y, z = RhinoCurve.from_guid(constraint).closest_point( mesh.vertex_coordinates(vkey)) elif rs.ObjectType(constraint) == 8: x, y, z = RhinoSurface.from_guid(constraint).closest_point( mesh.vertex_coordinates(vkey)) elif rs.ObjectType(constraint) == 32: x, y, z = RhinoMesh.from_guid(constraint).closest_point( mesh.vertex_coordinates(vkey)) else: continue mesh.vertex[vkey]['x'] = x mesh.vertex[vkey]['y'] = y mesh.vertex[vkey]['z'] = z
def RunCommand(is_interactive): scene = get_scene() if not scene: return proxy = get_proxy() if not proxy: return delaunay = proxy.function('compas.geometry.delaunay_from_points_numpy') # Get input data. surf_guid = compas_rhino.select_surface("Select a surface to decompose.") if not surf_guid: return point_guids = compas_rhino.select_points( "Select points to include in the decomposition.") curve_guids = [] compas_rhino.rs.HideObjects([surf_guid] + point_guids + curve_guids) surface = RhinoSurface.from_guid(surf_guid) curves = [RhinoCurve.from_guid(guid) for guid in curve_guids] points = [RhinoPoint.from_guid(guid) for guid in point_guids] # Compute the feature discretisation length. box = compas_rhino.rs.BoundingBox([surf_guid]) diagonal = compas_rhino.rs.Distance(box[0], box[6]) D = 0.05 * diagonal # Get the target length for the final quad mesh. L = compas_rhino.rs.GetReal( "Define the target edge length of the pattern.", 1.0) # Generate the pattern pattern = Pattern.from_surface_and_features(D, L, surf_guid, curve_guids, point_guids, delaunay=delaunay) scene.clear() scene.add(pattern, name='pattern') scene.update() kmax = 10 # Constrain mesh components to the feature geometry. constraints = automated_smoothing_surface_constraints(pattern, surface) constraints.update( automated_smoothing_constraints(pattern, rhinopoints=points, rhinocurves=curves)) while True: option = compas_rhino.rs.GetString("Smoothen the pattern?", "No", ["Yes", "No"]) if not option: break if option != "Yes": break constrained_smoothing(pattern, kmax=kmax, damping=0.5, constraints=constraints, algorithm="area") scene.update() print('Pattern object successfully created. Input object has been hidden.')