def my_mesh_thicken(mesh, thickness=1.0, cls=None): """Thicken a mesh. Parameters ---------- mesh : Mesh A mesh to thicken. thickness : real The mesh thickness Returns ------- thickened_mesh : Mesh The thickened mesh. """ if cls is None: cls = type(mesh) # offset in both directions mesh_top, mesh_bottom = map(lambda eps: my_mesh_offset(mesh, eps * thickness / 2., cls), [+1, -1]) # flip bottom part mesh_flip_cycles(mesh_bottom) # join parts thickened_mesh = meshes_join([mesh_top, mesh_bottom], cls) # close boundaries n = thickened_mesh.number_of_vertices() / 2 edges_on_boundary = [] for boundary in list(my_edges_on_boundaries(thickened_mesh)): edges_on_boundary.extend(boundary) for u, v in edges_on_boundary: if u < n and v < n: thickened_mesh.add_face([u, v, v + n, u + n]) return thickened_mesh
def _dae_mesh_importer(filename): """This is a very simple implementation of a DAE/Collada parser. It merges all solids of the DAE file into one mesh, because several other parts of the framework don't support multi-meshes per file.""" dae = XML.from_file(filename) meshes = [] for mesh_xml in dae.root.findall('.//mesh'): for triangle_set in mesh_xml.findall('triangles'): triangle_set_data = triangle_set.find('p').text.split() # Parse vertices vertices_input = triangle_set.find('input[@semantic="VERTEX"]') vertices_link = mesh_xml.find('vertices[@id="{}"]/input'.format(vertices_input.attrib['source'][1:])) positions = mesh_xml.find('source[@id="{}"]/float_array'.format(vertices_link.attrib['source'][1:])) positions = positions.text.split() vertices = list(map(float, positions[i:i + 3]) for i in range(0, len(positions), 3)) # Parse faces faces = list(map(int, triangle_set_data[::2])) # Ignore normals (ever second item is normal index) faces = list(faces[i:i + 3] for i in range(0, len(faces), 3)) mesh = Mesh.from_vertices_and_faces(vertices, faces) meshes.append(mesh) combined_mesh = meshes_join(meshes) # from compas.datastructures import mesh_transform # from compas.geometry import Frame # from compas.geometry import Transformation # former DAE files have yaxis and zaxis swapped # frame = Frame([0, 0, 0], [1, 0, 0], [0, 0, 1]) # T = Transformation.from_frame(frame) # mesh_transform(combined_mesh, T) return combined_mesh
# ============================================================================== # Main # ============================================================================== if __name__ == "__main__": import doctest import compas from compas.datastructures import Mesh from compas.datastructures import meshes_join from compas.geometry import translate_points_xy m1 = Mesh.from_obj(compas.get('faces.obj')) m2 = m1.copy() points = m2.vertices_attributes('xyz') x, y, z = zip(*points) xmin = min(x) xmax = max(x) points = translate_points_xy(points, [1.5 * (xmax - xmin), 0, 0]) for key, attr in m2.vertices(True): attr['x'] = points[key][0] attr['y'] = points[key][1] attr['z'] = points[key][2] m3 = meshes_join([m1, m2]) doctest.testmod()
def create_sk3_quad(lines, joint_width=1, leaf_width=1, joint_length=0.4): def get_convex_hull_mesh(points): faces = convex_hull(points) vertices = list(set(flatten(faces))) i_index = {i: index for index, i in enumerate(vertices)} vertices = [points[index] for index in vertices] faces = [[i_index[i] for i in face] for face in faces] faces = unify_cycles(vertices, faces) mesh = Mesh.from_vertices_and_faces(vertices, faces) return mesh def create_networks(): networks = {} descendent_tree = {} for u in joints: global_local = {} lines = [] nbrs = network_global.neighbors(u) start_pt = network_global.node_coordinates(u) for v in nbrs: end_pt = network_global.edge_point(u, v, t=joint_length) lines.append([start_pt, end_pt]) network_local = Network.from_lines(lines) key_local = list( set(list(network_local.nodes())) - set(network_local.leaves()))[0] global_local.update({u: key_local}) gkeys_global_network = [geometric_key(line[1]) for line in lines] gkeys_local_network = [ geometric_key(network_local.node_coordinates(key)) for key in network_local.leaves() ] for i, key_global in enumerate(nbrs): gkey_global = gkeys_global_network[i] index_local = gkeys_local_network.index(gkey_global) key_local = network_local.leaves()[index_local] global_local.update({key_global: key_local}) descendent_tree.update({u: global_local}) networks.update({u: network_local}) return networks, descendent_tree def create_sk3_branch(u, v): def find_vertices(u, v): sk3_joint_u = sk3_joints[u] # inside of network_u, find vertices on the verge leaf_u = descendent_tree[u][ v] # this is network local key, not convexhull mesh leaf_u = sk3_joint_u.network_convexhull[leaf_u] nbrs = sk3_joint_u.convexhull_mesh.vertex_neighbors(leaf_u, ordered=True) keys = [ sk3_joint_u.descendent_tree[leaf_u][nbr]['lp'] for nbr in nbrs ] points = [sk3_joint_u.vertex_coordinates(key) for key in keys] return points if u in joints and v in joints: # its an internal edge points_u = find_vertices(u, v) points_v = find_vertices(v, u) if len(points_u) != len(points_v): mesh = get_convex_hull_mesh(points_u + points_v) else: points_v = points_v[::-1] index = closest_point_in_cloud(points_u[0], points_v)[2] points_v = points_v[index:] + points_v[:index] vertices = points_u + points_v faces = [] n = len(points_u) for i in range(n): faces.append([i, (i + 1) % n, (i + 1) % n + n, i + n]) mesh = Mesh.from_vertices_and_faces(vertices, faces) else: if u in leafs: leaf, joint = u, v elif v in leafs: leaf, joint = v, u points_joint = find_vertices(joint, leaf) network = networks[joint] u_local = descendent_tree[joint][joint] v_local = descendent_tree[joint][leaf] vec = [ i * (1 - joint_length) for i in network_global.edge_vector(joint, leaf) ] points_leaf = [add_vectors(pt, vec) for pt in points_joint] vertices = points_joint + points_leaf faces = [] n = len(points_joint) for i in range(n): faces.append([i, (i + 1) % n, (i + 1) % n + n, i + n]) mesh = Mesh.from_vertices_and_faces(vertices, faces) return mesh def create_sk3_branches(): return [create_sk3_branch(u, v) for u, v in network_global.edges()] def create_sk3_joints(networks): sk3_joints = {} for u in networks: network = networks[u] sk3_joint = Skeleton3D_Node.from_network(network) sk3_joint.joint_width = joint_width sk3_joint.leaf_width = leaf_width sk3_joint.update_vertices_location() sk3_joints.update({u: sk3_joint}) return sk3_joints def draw_mesh_faces(mesh): fkeys_nodraw = [ fkey for fkey in mesh.faces() if mesh.face_area(fkey) <= 0 ] fkeys = list(set(list(mesh.faces())) - set(fkeys_nodraw)) artist = MeshArtist(mesh) artist.layer = '3GS::Skeleton' artist.draw_faces(faces=fkeys, join_faces=True) network_global = Network.from_lines(lines) joints = [] leafs = [] for key in network_global.node: if network_global.is_leaf(key): leafs.append(key) else: joints.append(key) networks, descendent_tree = create_networks() sk3_joints = create_sk3_joints(networks) sk3_branches = create_sk3_branches() mesh = meshes_join(sk3_joints.values() + sk3_branches) draw_mesh_faces(mesh) return mesh
[-30, 0, 0], [-30, -30, 0], [0, -30, 0], [30, -30, 0], ] for vector, mesh2 in zip(vectors, meshes): mesh2.collect_strips() fix_boundaries(mesh2) define_density(mesh2, 300) fix_boundaries(mesh2.get_quad_mesh()) find_form(mesh2.get_quad_mesh(), 100.0) mesh_move_by(mesh2.get_quad_mesh(), vector) rotate_mesh(mesh2.get_quad_mesh()) # for mesh2 in meshes: # if mesh2.get_quad_mesh() is None: # print('!') # for mesh in meshes: # plotter = MeshPlotter(mesh, figsize=(5.0, 5.0)) # plotter.draw_edges() # plotter.draw_faces() # plotter.show() all_meshes = meshes_join([mesh2.get_quad_mesh() for mesh2 in meshes]) plotter = MeshPlotter(all_meshes, figsize=(5.0, 5.0)) plotter.draw_edges() plotter.draw_faces() plotter.show()
r_axis = 3.0 r_pipe = 1.5 torus = Torus(plane, r_axis, r_pipe) vs, fs = torus.to_vertices_and_faces(u=11, v=11) torus_mesh = Mesh.from_vertices_and_faces(vs, fs) vertex_spheres = [] for v in torus_mesh.vertices(): v_coords = torus_mesh.vertex_coordinates(v) sphere = Sphere(v_coords, 0.2) vs, fs = sphere.to_vertices_and_faces(u=12, v=12) sphere_mesh = Mesh.from_vertices_and_faces(vs, fs) vertex_spheres.append(sphere_mesh) spheres_mesh = meshes_join(vertex_spheres) torus_and_spheres = meshes_join([spheres_mesh, torus_mesh]) edge_cylinders = [] for e in torus_mesh.edges(): e_mid = torus_mesh.edge_midpoint(e[0], e[1]) e_dir = torus_mesh.edge_direction(e[0], e[1]) e_len = torus_mesh.edge_length(e[0], e[1]) circle = Circle((e_mid, e_dir), 0.1) cylinder = Cylinder(circle, e_len) vs, fs = cylinder.to_vertices_and_faces(u=16) cyl_mesh = Mesh.from_vertices_and_faces(vs, fs) edge_cylinders.append(cyl_mesh)
def to_compas_quadmesh(self, nu, nv=None, weld=False, facefilter=None, cls=None): """Convert the surface to a COMPAS mesh. Parameters ---------- nu: int The number of faces in the u direction. nv: int, optional The number of faces in the v direction. Default is the same as the u direction. weld: bool, optional Weld the vertices of the mesh. Default is ``False``. facefilter: callable, optional A filter for selection which Brep faces to include. If provided, the filter should return ``True`` or ``False`` per face. A very simple filter that includes all faces is ``def facefilter(face): return True``. Default parameter value is ``None`` in which case all faces are included. cls: :class:`compas.geometry.Mesh`, optional The type of COMPAS mesh. Returns ------- :class:`compas.geometry.Mesh` """ nv = nv or nu cls = cls or Mesh if not self.geometry.HasBrepForm: return brep = Rhino.Geometry.Brep.TryConvertBrep(self.geometry) if facefilter and callable(facefilter): faces = [face for face in brep.Faces if facefilter(face)] else: faces = brep.Faces meshes = [] for face in faces: domain_u = face.Domain(0) domain_v = face.Domain(1) du = (domain_u[1] - domain_u[0]) / (nu) dv = (domain_v[1] - domain_v[0]) / (nv) @memoize def point_at(i, j): return point_to_compas(face.PointAt(i, j)) quads = [] for i in range(nu): for j in range(nv): a = point_at(domain_u[0] + (i + 0) * du, domain_v[0] + (j + 0) * dv) b = point_at(domain_u[0] + (i + 1) * du, domain_v[0] + (j + 0) * dv) c = point_at(domain_u[0] + (i + 1) * du, domain_v[0] + (j + 1) * dv) d = point_at(domain_u[0] + (i + 0) * du, domain_v[0] + (j + 1) * dv) quads.append([a, b, c, d]) meshes.append(cls.from_polygons(quads)) return meshes_join(meshes, cls=cls)