def smooth_mesh_centerofmass(mesh, fixed=None, kmax=1, d=1.0, callback=None, callback_args=None): """""" if callback: if not callable(callback): raise Exception('Callback is not callable.') fixed = fixed or [] fixed = set(fixed) for k in range(kmax): key_xyz = {key: mesh.vertex_coordinates(key) for key in mesh} for key in mesh.vertices(): if key in fixed: continue p = key_xyz[key] nbrs = mesh.vertex_neighbours(key, ordered=True) c = center_of_mass_polygon([key_xyz[nbr] for nbr in nbrs]) # update attr = mesh.vertex[key] attr['x'] += d * (c[0] - p[0]) attr['y'] += d * (c[1] - p[1]) attr['z'] += d * (c[2] - p[2]) if callback: callback(mesh, k, callback_args)
def _face_to_max_quad(points, face): faces = [] c = len(points) points.append(center_of_mass_polygon(points)) for i in range(-1, len(face) - 1): a = face[i] b = face[i + 1] faces.append([c, a, b, b]) return faces
def face_center(self, fkey): """Return the location of the center of mass of a face.""" return center_of_mass_polygon(self.face_coordinates(fkey))
def center(self): """The center (of mass) of the polygon.""" return Point(* center_of_mass_polygon(self.points))
def mesh_smooth_centerofmass(mesh, fixed=None, kmax=100, damping=0.5, callback=None, callback_args=None): """Smooth a mesh by moving every free vertex to the center of mass of the polygon formed by the neighbouring vertices. Parameters ---------- mesh : Mesh A mesh object. fixed : list, optional The fixed vertices of the mesh. kmax : int, optional The maximum number of iterations. damping : float, optional The damping factor. callback : callable, optional A user-defined callback function to be executed after every iteration. callback_args : list, optional A list of arguments to be passed to the callback. Raises ------ Exception If a callback is provided, but it is not callable. Examples -------- .. plot:: :include-source: import compas from compas.datastructures import Mesh from compas.plotters import MeshPlotter from compas.geometry import mesh_smooth_centerofmass mesh = Mesh.from_obj(compas.get('faces.obj')) fixed = [key for key in mesh.vertices() if mesh.vertex_degree(key) == 2] mesh_smooth_centerofmass(mesh, fixed=fixed) plotter = MeshPlotter(mesh) plotter.draw_vertices(facecolor={key: '#ff0000' for key in fixed}) plotter.draw_faces() plotter.draw_edges() plotter.show() See Also -------- * :func:`mesh_smooth_area` """ if callback: if not callable(callback): raise Exception('Callback is not callable.') fixed = fixed or [] fixed = set(fixed) for k in range(kmax): key_xyz = { key: mesh.vertex_coordinates(key) for key in mesh.vertices() } for key, attr in mesh.vertices(True): if key in fixed: continue x, y, z = key_xyz[key] cx, cy, cz = center_of_mass_polygon( [key_xyz[nbr] for nbr in mesh.vertex_neighbours(key)]) attr['x'] += damping * (cx - x) attr['y'] += damping * (cy - y) attr['z'] += damping * (cz - z) if callback: callback(k, callback_args)
def smooth_centerofmass(vertices, adjacency, fixed=None, kmax=1, damping=0.5, callback=None, callback_args=None): """Smooth a connected set of vertices by moving each vertex to the center of mass of the polygon formed by the neighbouring vertices. Parameters ---------- verticses : dict A dictionary of vertex coordinates. adjacency : dict Adjacency information for each of the vertices. fixed : list, optional The fixed vertices of the mesh. kmax : int, optional The maximum number of iterations. d : float, optional The damping factor. callback : callable, optional A user-defined callback function to be executed after every iteration. callback_args : list, optional A list of arguments to be passed to the callback. Raises ------ Exception If a callback is provided, but it is not callable. Notes ----- When using this algorithm in combination with one of the datastructures (as in the example below), note that the neighbours of each vertex have to be listed in order, i.e. they have to form a polygon without self-intersections. Examples -------- .. plot:: :include-source: import compas from compas.datastructures import Mesh from compas.geometry import smooth_centerofmass from compas.plotters import MeshPlotter mesh = Mesh.from_obj(compas.get('faces.obj')) vertices = mesh.get_vertices_attributes('xyz') neighbours = [mesh.vertex_neighbours(key) for key in mesh.vertices()] fixed = [key for key in mesh.vertices() if mesh.vertex_degree(key) == 2] lines = [] for u, v in mesh.edges(): lines.append({ 'start': mesh.vertex_coordinates(u, 'xy'), 'end' : mesh.vertex_coordinates(v, 'xy'), 'color': '#cccccc', 'width': 1.0, }) smooth_centerofmass(vertices, neighbours, fixed=fixed, kmax=100) for key, attr in mesh.vertices(True): attr['x'] = vertices[key][0] attr['y'] = vertices[key][1] attr['z'] = vertices[key][2] plotter = MeshPlotter(mesh) plotter.draw_lines(lines) plotter.draw_vertices(facecolor={key: '#ff0000' for key in fixed}) plotter.draw_edges() plotter.show() See Also -------- * :func:`smooth_centroid` * :func:`smooth_area` """ fixed = fixed or [] fixed = set(fixed) if callback: if not callable(callback): raise Exception('The callback is not callable.') for k in range(kmax): xyz_0 = [xyz[:] for xyz in vertices] for index, point in enumerate(xyz_0): if index in fixed: continue nbrs = adjacency[index] com = center_of_mass_polygon([xyz_0[nbr] for nbr in nbrs]) vertices[index][0] += damping * (com[0] - point[0]) vertices[index][1] += damping * (com[1] - point[1]) vertices[index][2] += damping * (com[2] - point[2]) if callback: callback(k, callback_args)
def network_smooth_mass(network, fixed=None, kmax=1, d=0.5, callback=None, callback_args=None): """Smooth a network using per vertex the center of mass of the polygon formed by the neighbouring vertices. Parameters: network (compas.datastructures.network.Network): The network object. fixed (list): Optional. The fixed vertices of the network. Default is ``None``. kmax (int): Optional. The maximum number of iterations. Default is ``1``. d (float): Optional. The damping factor. Default is ``0.5``. callback (callable): Optional. A user-defined callback function to be executed after every iteration. Default is ``None``. Raises: Exception: If a callback is provided, but not callable. Example: .. plot:: :include-source: import compas from compas.datastructures.network import Network from compas.visualization.plotters import NetworkPlotter from compas.datastructures.network.algorithms import network_find_faces from compas.datastructures.network.algorithms import network_smooth_mass network = Network.from_obj(compas.get_data('grid_irregular.obj')) network_find_faces(network, network.leaves()) network_smooth_mass(network, fixed=network.leaves(), kmax=10) plotter = NetworkPlotter(network) plotter.draw_vertices() plotter.draw_edges() plotter.show() """ fixed = fixed or [] fixed = set(fixed) if callback: if not callable(callback): raise Exception('The callback is not callable.') for k in range(kmax): key_xyz = { key: network.vertex_coordinates(key) for key in network.vertices() } for key in network: if key in fixed: continue nbrs = network.vertex_neighbours(key, ordered=True) points = [key_xyz[nbr] for nbr in nbrs] cx, cy, cz = center_of_mass_polygon(points) x, y, z = key_xyz[key] attr = network.vertex[key] attr['x'] += d * (cx - x) attr['y'] += d * (cy - y) attr['z'] += d * (cz - z) if callback: callback(network, k, callback_args)