def decomposition_skeleton(srf_guid, decomposition): # output remapped topological skeleton/medial axis return [ RhinoSurface(srf_guid).polyline_uv_to_xyz( [xyz[:2] for xyz in polyline]) for polyline in decomposition.branches() ]
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 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 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(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 in srf.borders(type=i): border = RhinoCurve(border) points = [ list(srf.point_xyz_to_uv(pt)) + [0.0] for pt in border.divide( max( int(border.length() / discretisation) + 1, minimum_discretisation)) ] if border.is_closed(): 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(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
srf_guid, float(triangulation_precision), crv_guids=crv_guids, pt_guids=pt_guids) coarse_quad_mesh = decomposition_mesh(srf_guid, decomposition, point_features) # density print 'densification...' coarse_quad_mesh.collect_strips() coarse_quad_mesh.set_strips_density(1) coarse_quad_mesh.set_strips_density_target(float(density_target)) coarse_quad_mesh.densification() # smoothing print 'smoothing...' constraints = automated_smoothing_surface_constraints( coarse_quad_mesh.get_quad_mesh(), RhinoSurface.from_guid(srf_guid)) constraints.update( automated_smoothing_constraints(coarse_quad_mesh.get_quad_mesh(), pt_guids)) constrained_smoothing(coarse_quad_mesh.get_quad_mesh(), kmax=int(kmax), damping=float(damping), constraints=constraints, algorithm='area') for obj in set(constraints.values()): if rs.ObjectType(obj) != 8: rs.DeleteObject(obj) rs.EnableRedraw(False) MeshArtist(coarse_quad_mesh.get_quad_mesh()).draw_mesh()
def surface_decomposition(srf_guid, precision, crv_guids=[], pt_guids=[], output_delaunay=False, output_skeleton=True, output_decomposition=False, output_mesh=True, output_polysurface=False, src='numpy_rpc'): """Generate the topological skeleton/medial axis of a surface based on a Delaunay triangulation, after mapping and before remapping. Parameters ---------- srf_guid : guid A Rhino surface guid. precision : float A discretisation precision. crv_guids : list A list of Rhino curve guids. pt_guids : list A list of Rhino points guids. output_delaunay : bool Output the Delaunay mesh or not. Default is False. output_skeleton : bool Output the skeleton polylines or not. Default is True. output_decomposition : bool Output the decomposition polylines or not. Default is True. output_mesh : bool Output the coarse quad mesh or not. Default is True. output_polysurface : bool Output the polysurface or not. Default is False. src : str Source of Delaunay triangulation algorithm. Returns ------- list The requested outputs. References ---------- .. [1] Harry Blum. 1967. *A transformation for extracting new descriptors of shape*. Models for Perception of Speech and Visual Forms, pages 362--380. Available at http://pageperso.lif.univ-mrs.fr/~edouard.thiel/rech/1967-blum.pdf. .. [2] Punam K. Saha, Gunilla Borgefors, and Gabriella Sanniti di Baja. 2016. *A survey on skeletonization algorithms and their applications*. Pattern Recognition Letters, volume 76, pages 3--12. Available at https://www.sciencedirect.com/science/article/abs/pii/S0167865515001233. .. [3] Oval et al. 2019. *Feature-based topology finding of patterns for shell structures*. Accepted in Automation in Construction. """ # mapping NURBS surface to planar polyline borders outer_boundary, inner_boundaries, polyline_features, point_features = surface_discrete_mapping( srf_guid, precision, crv_guids=crv_guids, pt_guids=pt_guids) # Delaunay triangulation of the palnar polyline borders decomposition = boundary_triangulation(outer_boundary, inner_boundaries, polyline_features, point_features, cls=Decomposition, src=src) outputs = [] # output remapped Delaunay mesh if output_delaunay: outputs.append(RhinoSurface(srf_guid).mesh_uv_to_xyz(decomposition)) # output remapped topological skeleton/medial axis if output_skeleton: outputs.append([ RhinoSurface(srf_guid).polyline_uv_to_xyz( [xyz[:2] for xyz in polyline]) for polyline in decomposition.branches() ]) if output_decomposition: outputs.append([ RhinoSurface(srf_guid).polyline_uv_to_xyz( [xyz[:2] for xyz in polyline]) for polyline in decomposition.decomposition_polylines() ]) # output decomposition coarse quad mesh if output_mesh: mesh = decomposition.decomposition_mesh(point_features) RhinoSurface(srf_guid).mesh_uv_to_xyz(mesh) outputs.append(mesh) # output decomposition surface if output_polysurface: mesh = decomposition.decomposition_mesh() nurbs_curves = { (geometric_key(polyline[i]), geometric_key(polyline[-i - 1])): rs.AddInterpCrvOnSrfUV(srf_guid, [pt[:2] for pt in polyline]) for polyline in decomposition.decomposition_polylines() for i in [0, -1] } outputs.append( rs.JoinSurfaces([ rs.AddEdgeSrf([ nurbs_curves[(geometric_key(mesh.vertex_coordinates(u)), geometric_key(mesh.vertex_coordinates(v)))] for u, v in mesh.face_halfedges(fkey) ]) for fkey in mesh.faces() ], delete_input=True)) rs.DeleteObjects(list(nurbs_curves.values())) return outputs
def editing_geometry_smoothing(coarse_pseudo_quad_mesh): """Edit the geometry of a pattern with smoothing. Parameters ---------- coarse_pseudo_quad_mesh : CoarsePseudoQuadMesh The pattern to edit. """ mesh_to_smooth = rs.GetString('mesh to smooth?', strings=[ 'coarse_pseudo_quad_mesh', 'pseudo_quad_mesh', 'polygonal_mesh' ]) if mesh_to_smooth == 'coarse_pseudo_quad_mesh': mesh = coarse_pseudo_quad_mesh elif mesh_to_smooth == 'pseudo_quad_mesh': mesh = coarse_pseudo_quad_mesh.get_quad_mesh elif mesh_to_smooth == 'polygonal_mesh': mesh = coarse_pseudo_quad_mesh.get_polygonal_mesh() else: return 0 settings = {'iterations': 50, 'damping': .5, 'constraints': {}} while True: rs.EnableRedraw(False) artist = rhino_artist.MeshArtist(mesh) guid = artist.draw_mesh() rs.EnableRedraw(True) operation = rs.GetString( 'edit smoothing settings?', strings=['smooth', 'iterations', 'damping', 'constraints', 'exit']) if operation is None or operation == 'exit': if type(guid) == list: rs.DeleteObjects(guid) else: rs.DeleteObject(guid) break elif operation == 'iterations': settings[operation] = rs.GetInteger('iterations', number=settings[operation], minimum=0) elif operation == 'damping': settings[operation] = rs.GetReal('damping', number=settings[operation], minimum=0., maximum=1.) elif operation == 'constraints': count = 100 while count: count -= 1 guids = display_smoothing_constraints(mesh, settings[operation]) constraint_type = rs.GetString('type of constraints?', strings=[ 'automated_from_surface', 'automated_from_objects', 'customised', 'reset', 'exit' ]) rs.DeleteObjects(guids) if constraint_type == 'automated_from_surface': settings[ operation] = automated_smoothing_surface_constraints( mesh, RhinoSurface( rs.GetObject('surface constraints', filter=8))) elif constraint_type == 'automated_from_objects': object_constraints = rs.GetObjects('object constraints') point_constraints = [ obj for obj in object_constraints if rs.ObjectType(obj) == 1 ] curve_constraints = [ obj for obj in object_constraints if rs.ObjectType(obj) == 4 ] surface_constraint = [ obj for obj in object_constraints if rs.ObjectType(obj) == 8 ] if len(surface_constraint) > 1: print( 'More than one surface constraint! Only the first one is taken into account.' ) if len(surface_constraint) == 0: surface_constraint = None else: surface_constraint = surface_constraint[0] settings[operation] = automated_smoothing_constraints( mesh, point_constraints, curve_constraints, surface_constraint) elif constraint_type == 'customised': settings[operation] = customized_smoothing_constraints( mesh, settings[operation]) elif constraint_type == 'reset': artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist') artist.clear_layer() artist.draw_vertices() artist.redraw() vkeys = rhino_helper.mesh_select_vertices( mesh, message='vertices') if vkeys is None: vkeys = list(mesh.vertices()) artist.clear_layer() artist.redraw() rs.DeleteLayer('mesh_artist') for vkey in vkeys: if vkey in settings[operation]: del settings[operation][vkey] else: break elif operation == 'smooth': constrained_smoothing(mesh, kmax=settings['iterations'], damping=settings['damping'], constraints=settings['constraints'], algorithm='area') if type(guid) == list: rs.DeleteObjects(guid) else: rs.DeleteObject(guid) if mesh_to_smooth == 'coarse_pseudo_quad_mesh': coarse_pseudo_quad_mesh = mesh elif mesh_to_smooth == 'pseudo_quad_mesh': coarse_pseudo_quad_mesh.set_quad_mesh(mesh) coarse_pseudo_quad_mesh.set_polygonal_mesh(mesh.copy()) elif mesh_to_smooth == 'polygonal_mesh': coarse_pseudo_quad_mesh.set_polygonal_mesh(mesh)
from compas_pattern.algorithms.relaxation.relaxation import constrained_smoothing from compas_rhino.artists import MeshArtist guid = rs.GetObject('get mesh', filter=32) srf_guid = rs.GetObject('get surface', filter=8) crv_guids = rs.GetObjects('get curves', filter=4) pt_guids = rs.GetObjects('get points', filter=1) rs.EnableRedraw(False) vertices = rs.MeshVertices(guid) faces = [list(face) for face in rs.MeshFaceVertices(guid)] mesh = Mesh.from_vertices_and_faces(vertices, faces) if srf_guid is not None: constraints = automated_smoothing_surface_constraints( mesh, RhinoSurface(srf_guid)) else: constraints = {} if crv_guids is not None: for vkey in mesh.vertices(): if not mesh.is_vertex_on_boundary(vkey): for crv_guid in crv_guids: if rs.IsPointOnCurve(crv_guid, mesh.vertex_coordinates(vkey)): constraints[vkey] = crv_guid break constraints.update(automated_smoothing_constraints(mesh, pt_guids)) kmax = rs.GetInteger('number of smoothing iterations?', 20, 0, 100) damping = rs.GetReal('value of smoothing damping?', 0.5, 0, 1)
def decomposition_mesh(srf_guid, decomposition, point_features): # output decomposition coarse quad mesh mesh = decomposition.decomposition_mesh(point_features) RhinoSurface.from_guid(srf_guid).mesh_uv_to_xyz(mesh) return mesh
def decomposition_curves(srf_guid, decomposition): return [ RhinoSurface(srf_guid).polyline_uv_to_xyz( [xyz[:2] for xyz in polyline]) for polyline in decomposition.decomposition_polylines() ]
def decomposition_delaunay(srf_guid, decomposition): # output remapped Delaunay mesh return RhinoSurface(srf_guid).mesh_uv_to_xyz(decomposition)
# topology print 'decomposition...' coarse_quad_mesh = surface_decomposition(srf_guid, float(triangulation_precision), crv_guids=crv_guids, pt_guids=pt_guids, output_delaunay=False, output_skeleton=False, output_mesh=True, output_polysurface=False)[0] # density print 'densification...' coarse_quad_mesh.init_strip_density() coarse_quad_mesh.set_strips_density_target(float(density_target)) coarse_quad_mesh.densification() # smoothing print 'smoothing...' constraints = automated_smoothing_surface_constraints( coarse_quad_mesh.quad_mesh, RhinoSurface(srf_guid)) constraints.update( automated_smoothing_constraints(coarse_quad_mesh.quad_mesh, pt_guids)) constrained_smoothing(coarse_quad_mesh.quad_mesh, kmax=int(kmax), damping=float(damping), constraints=constraints, algorithm='area') rs.EnableRedraw(False) draw_mesh(coarse_quad_mesh.quad_mesh)