def draw_geometry(self, geometry, name=None, color=None): # Imported colors take priority over a the parameter color if 'mesh_color.diffuse' in geometry.attributes: color = geometry.attributes['mesh_color.diffuse'] key_index = geometry.key_index() vertices = geometry.vertices_attributes('xyz') faces = [[key_index[key] for key in geometry.face_vertices(fkey)] for fkey in geometry.faces()] new_faces = [] for face in faces: f = len(face) if f == 3: new_faces.append(face + face[-1:]) elif f == 4: new_faces.append(face) elif f > 4: centroid = len(vertices) vertices.append( centroid_polygon([vertices[index] for index in face])) for a, b in pairwise(face + face[0:1]): new_faces.append([centroid, a, b, b]) else: continue mesh = Rhino.Geometry.Mesh() if name: mesh.UserDictionary.Set('MeshName', name) if color: r, g, b, a = color mesh.UserDictionary.Set('MeshColor.R', r) mesh.UserDictionary.Set('MeshColor.G', g) mesh.UserDictionary.Set('MeshColor.B', b) mesh.UserDictionary.Set('MeshColor.A', a) for v in vertices: mesh.Vertices.Add(*v) for face in new_faces: mesh.Faces.AddFace(*face) mesh.Normals.ComputeNormals() mesh.Compact() # Try to fix invalid meshes if not mesh.IsValid: mesh.FillHoles() return mesh
def face_center(self, fkey): """Compute the location of the center of mass of a face. Parameters ---------- fkey : int The identifier of the face. Returns ------- list The coordinates of the center of mass. """ return centroid_polygon(self.face_coordinates(fkey))
def draw_mesh(self, color=(0, 0, 0), disjoint=False): """Draw the mesh as a consolidated RhinoMesh. Parameters ---------- color : tuple, optional The color of the mesh. Default is black, ``(0, 0, 0)``. disjoint : bool, optional Draw the faces of the mesh with disjoint vertices. Default is ``False``. Returns ------- list The GUIDs of the created Rhino objects. Notes ----- The mesh should be a valid Rhino Mesh object, which means it should have only triangular or quadrilateral faces. Faces with more than 4 vertices will be triangulated on-the-fly. """ vertex_index = self.mesh.key_index() vertex_xyz = self.vertex_xyz vertices = [vertex_xyz[vertex] for vertex in self.mesh.vertices()] faces = [[vertex_index[vertex] for vertex in self.mesh.face_vertices(face)] for face in self.mesh.faces()] new_faces = [] for face in faces: f = len(face) if f == 3: new_faces.append(face + face[-1:]) elif f == 4: new_faces.append(face) elif f > 4: centroid = len(vertices) vertices.append(centroid_polygon([vertices[index] for index in face])) for a, b in pairwise(face + face[0:1]): new_faces.append([centroid, a, b, b]) else: continue layer = self.layer name = "{}".format(self.mesh.name) guid = compas_rhino.draw_mesh(vertices, new_faces, layer=layer, name=name, color=color, disjoint=disjoint) return [guid]
def draw_mesh(self, color=None, disjoint=False): """Draw the mesh as a consolidated RhinoMesh. Parameters ---------- color : 3-tuple, optional RGB color components in integer format (0-255). disjoint : bool, optional Draw the faces of the mesh with disjoint vertices. Default is ``False``. Returns ------- list The GUIDs of the created Rhino objects. Notes ----- The mesh should be a valid Rhino Mesh object, which means it should have only triangular or quadrilateral faces. Faces with more than 4 vertices will be triangulated on-the-fly. """ key_index = self.mesh.key_index() vertices = self.mesh.vertices_attributes('xyz') faces = [[key_index[key] for key in self.mesh.face_vertices(fkey)] for fkey in self.mesh.faces()] new_faces = [] for face in faces: f = len(face) if f == 3: new_faces.append(face + face[-1:]) elif f == 4: new_faces.append(face) elif f > 4: centroid = len(vertices) vertices.append(centroid_polygon([vertices[index] for index in face])) for a, b in pairwise(face + face[0:1]): new_faces.append([centroid, a, b, b]) else: continue layer = self.layer name = "{}.mesh".format(self.mesh.name) guid = compas_rhino.draw_mesh(vertices, new_faces, layer=layer, name=name, color=color, disjoint=disjoint) self.guids += [guid] return [guid]
def draw_mesh(self, color=None): key_index = self.mesh.key_index() vertices = self.mesh.vertices_attributes('xyz') faces = [[key_index[key] for key in self.mesh.face_vertices(fkey)] for fkey in self.mesh.faces()] new_faces = [] for face in faces: f = len(face) if f == 3: new_faces.append(face + [face[-1]]) elif f == 4: new_faces.append(face) elif f > 4: centroid = len(vertices) vertices.append( centroid_polygon([vertices[index] for index in face])) for a, b in pairwise(face + face[0:1]): new_faces.append([centroid, a, b, b]) else: continue return compas_ghpython.draw_mesh(vertices, new_faces, color)
def draw_mesh(self, color=None, disjoint=False): """Draw the mesh as a consolidated RhinoMesh. Notes ----- The mesh should be a valid Rhino Mesh object, which means it should have only triangular or quadrilateral faces. """ key_index = self.mesh.key_index() vertices = self.mesh.get_vertices_attributes('xyz') faces = [[key_index[key] for key in self.mesh.face_vertices(fkey)] for fkey in self.mesh.faces()] new_faces = [] for face in faces: f = len(face) if f == 3: new_faces.append(face + face[-1:]) elif f == 4: new_faces.append(face) elif f > 4: centroid = len(vertices) vertices.append( centroid_polygon([vertices[index] for index in face])) for a, b in pairwise(face + face[0:1]): new_faces.append([centroid, a, b, b]) else: continue layer = self.layer name = "{}.mesh".format(self.mesh.name) return compas_rhino.draw_mesh(vertices, new_faces, layer=layer, name=name, color=color, disjoint=disjoint)
def get_area_convex_2d_polygon(polygon): """ Computes the area of a convex 2d polygon by using cross product """ area = 0 centroid = centroid_polygon(polygon) centroid_vect = Vector(centroid[0], centroid[1], centroid[2]) for i in range(len(polygon)): pt1 = Vector(polygon[i][0], polygon[i][1], polygon[i][2]) pt2 = Vector(polygon[i-1][0], polygon[i-1][1], polygon[i-1][2]) vect_side1 = pt1 - centroid_vect vect_side2 = pt2 - centroid_vect cross = cross_vectors(vect_side1, vect_side2) cross_length = length_vector(cross) face_area = cross_length / 2 area += face_area print(area) return area
def centroid(self): """int : The centroid of the polygon.""" point = centroid_polygon(self.points) return Point(*point)
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 neighboring 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 neighbors 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') adjacency = [mesh.vertex_neighbors(key, ordered=True) 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, adjacency, 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() """ 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 com = centroid_polygon([xyz_0[nbr] for nbr in adjacency[index]]) 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 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 neighboring 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 -------- >>> """ 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 = centroid_polygon([ key_xyz[nbr] for nbr in mesh.vertex_neighbors(key, ordered=True) ]) attr['x'] += damping * (cx - x) attr['y'] += damping * (cy - y) attr['z'] += damping * (cz - z) if callback: callback(k, callback_args)
def draw_mesh(vertices, faces, name=None, color=None, disjoint=False, **kwargs): """Draw a mesh and optionally set individual name, color, and layer properties. Parameters ---------- vertices : :obj:`list` of point A list of point locations. faces : :obj:`list` of :obj:`list` of :obj:`int` A list of faces as lists of indices into ``vertices``. name : :obj:`str`, optional color : RGB :obj:`tuple`, optional disjoint : :obj:`bool`, optional Draw the mesh with disjoint faces. Default is ``False``. Returns ------- str or GUID """ mesh = RhinoMesh() if disjoint: for face in faces: f = len(face) if f < 3: continue if f == 3: a = mesh.Vertices.Add(* vertices[face[0]]) b = mesh.Vertices.Add(* vertices[face[1]]) c = mesh.Vertices.Add(* vertices[face[2]]) mesh.Faces.AddFace(a, b, c) elif f == 4: a = mesh.Vertices.Add(* vertices[face[0]]) b = mesh.Vertices.Add(* vertices[face[1]]) c = mesh.Vertices.Add(* vertices[face[2]]) d = mesh.Vertices.Add(* vertices[face[3]]) mesh.Faces.AddFace(a, b, c, d) else: if MeshNgon: points = [vertices[vertex] for vertex in face] centroid = centroid_polygon(points) indices = [] for point in points: indices.append(mesh.Vertices.Add(* point)) c = mesh.Vertices.Add(* centroid) facets = [] for i, j in pairwise(indices + indices[:1]): facets.append(mesh.Faces.AddFace(i, j, c)) ngon = MeshNgon.Create(indices, facets) mesh.Ngons.AddNgon(ngon) else: for x, y, z in vertices: mesh.Vertices.Add(x, y, z) for face in faces: f = len(face) if f < 3: continue if f == 3: mesh.Faces.AddFace(*face) elif f == 4: mesh.Faces.AddFace(*face) else: if MeshNgon: centroid = centroid_polygon([vertices[index] for index in face]) c = mesh.Vertices.Add(* centroid) facets = [] for i, j in pairwise(face + face[:1]): facets.append(mesh.Faces.AddFace(i, j, c)) ngon = MeshNgon.Create(face, facets) mesh.Ngons.AddNgon(ngon) mesh.Normals.ComputeNormals() mesh.Compact() guid = add_mesh(mesh) if guid != System.Guid.Empty: obj = find_object(guid) if obj: attr = obj.Attributes if color: attr.ObjectColor = FromArgb(*color) attr.ColorSource = ColorFromObject else: attr.ColorSource = ColorFromLayer if name: attr.Name = name obj.CommitChanges() return guid
def create_geometry(self, geometry, name=None, color=None): """Create a Rhino mesh corresponding to the geometry of the model. Parameters ---------- geometry : :class:`compas.datastructures.Mesh` A COMPAS mesh data structure. name : str, optional Name of the mesh object. color : tuple[int, int, int], optional Color of the mesh object. Returns ------- :rhino:`Rhino.Geometry.Mesh` """ # Imported colors take priority over a the parameter color if 'mesh_color.diffuse' in geometry.attributes: color = geometry.attributes['mesh_color.diffuse'] key_index = geometry.key_index() vertices = geometry.vertices_attributes('xyz') faces = [[key_index[key] for key in geometry.face_vertices(fkey)] for fkey in geometry.faces()] new_faces = [] for face in faces: f = len(face) if f == 3: new_faces.append(face + face[-1:]) elif f == 4: new_faces.append(face) elif f > 4: centroid = len(vertices) vertices.append(centroid_polygon([vertices[index] for index in face])) for a, b in pairwise(face + face[0:1]): new_faces.append([centroid, a, b, b]) else: continue mesh = Rhino.Geometry.Mesh() if name: mesh.UserDictionary.Set('MeshName', name) if color: r, g, b, a = color mesh.UserDictionary.Set('MeshColor.R', r) mesh.UserDictionary.Set('MeshColor.G', g) mesh.UserDictionary.Set('MeshColor.B', b) mesh.UserDictionary.Set('MeshColor.A', a) for v in vertices: mesh.Vertices.Add(*v) for face in new_faces: mesh.Faces.AddFace(*face) mesh.Normals.ComputeNormals() mesh.Compact() # Try to fix invalid meshes if not mesh.IsValid: mesh.FillHoles() return mesh
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 neighboring 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.datastructures import mesh_smooth_centerofmass from compas_plotters import MeshPlotter 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() """ 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 = centroid_polygon([key_xyz[nbr] for nbr in mesh.vertex_neighbors(key, ordered=True)]) attr['x'] += damping * (cx - x) attr['y'] += damping * (cy - y) attr['z'] += damping * (cz - z) if callback: callback(k, callback_args)
def face_center(self, fkey): """Return the location of the center of mass of a face.""" return centroid_polygon(self.face_coordinates(fkey))
def centroid(self): point = centroid_polygon(self.points) return Point(*point)