def get_transformed_model(self, transformation, xtransform_function=None): """Get the transformed meshes of the tool model. Args: transformation (:class:`Transformation`): The transformation to reach tool0_frame. xform_function (function name, optional): the name of the function used to transform the model. Defaults to None. Returns: model (:obj:`list` of :class:`Mesh`): The list of meshes in the respective class of the CAD environment """ tmodel = [] if xtransform_function: for m in self.model: tmodel.append(xtransform_function(m, transformation, copy=True)) else: for m in self.model: mtxyz = transform_point(m.xyz, transformation) faces = [m.face_vertices(fkey) for fkey in m.faces()] tmodel.append(Mesh.from_vertices_and_faces(mtxyz, faces)) return tmodel for m in self.model: mtxyz = transform_point(m.xyz, transformation) mtxyz = transform_points(m.xyz, transformation) faces = [m.face_vertices(fkey) for fkey in m.faces()] tmodel.append(Mesh.from_vertices_and_faces(mtxyz, faces))
def build_meshes(boxes, plane): beams = [extrude_normal(box, BEAM_WIDTH, plane) for box in boxes] faces = [[0, 3, 2, 1], [4, 5, 6, 7], [3, 0, 4, 7], [2, 3, 7, 6], [1, 2, 6, 5], [0, 1, 5, 4]] # faces = [[0, 1, 2, 3], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]] meshes = [Mesh.from_vertices_and_faces(points, faces) for points in beams] return meshes
def test_booleans(): # ============================================================================== # Make a box and a sphere # ============================================================================== box = Box.from_width_height_depth(2, 2, 2) box = Mesh.from_shape(box) box.quads_to_triangles() A = box.to_vertices_and_faces() sphere = Sphere(Point(1, 1, 1), 1) sphere = Mesh.from_shape(sphere, u=30, v=30) sphere.quads_to_triangles() B = sphere.to_vertices_and_faces() # ============================================================================== # Remesh the sphere # ============================================================================== B = remesh(B, 0.3, 10) # ============================================================================== # Compute the boolean mesh # ============================================================================== V, F = boolean_union(A, B) mesh = Mesh.from_vertices_and_faces(V, F)
def reconstruct_mesh_from_faces(self, mesh, fkeys): active_keys = {} new_faces = {} count = 0 # get new faces for fkey in fkeys: new_face = [] for vkey in mesh.face_vertices(fkey): if vkey not in active_keys: active_keys[vkey] = count count += 1 new_face.append(active_keys.get(vkey)) new_faces[fkey] = new_face # get new vertices new_vertices = [] for a_key, idx in active_keys.items(): new_vertices.append((mesh.vertex_coordinates(a_key), idx)) new_vertices = sorted(new_vertices, key=lambda x: x[1]) new_vertices = [x[0] for x in new_vertices] # retrieve face list new_faces = [face for fkey, face in new_faces.items()] # create new mesh new_mesh = Mesh.from_vertices_and_faces(new_vertices, new_faces) return new_mesh
def to_mesh(self, nu=100, nv=None): """Convert the surface to a quad mesh. Parameters ---------- nu : int, optional Number of faces in the U direction. nv : int, optional Number of faces in the V direction. Returns ------- :class:`compas.datastructures.Mesh` """ from compas.datastructures import Mesh nv = nv or nu vertices = [self.point_at(i, j) for i, j in product(self.u_space(nu + 1), self.v_space(nv + 1))] faces = [[ i * (nv + 1) + j, (i + 1) * (nv + 1) + j, (i + 1) * (nv + 1) + j + 1, i * (nv + 1) + j + 1 ] for i, j in product(range(nu), range(nv))] return Mesh.from_vertices_and_faces(vertices, faces)
def find_devisions(mesh, edge_groups, trg_len): for edges in edge_groups: lengths = 0 for u, v in edges: lengths += mesh.get_edge_attribute((u, v), 'length') ave_len = lengths / len(edges) div = max((round(ave_len / trg_len, 0), 1)) for u, v in edges: crv = mesh.get_edge_attribute((u, v), 'guid') pts = rs.DivideCurve(crv, div) mesh.set_edge_attribute((u, v), 'points', pts) edges = set(mesh.edges()) coons_meshes = [] for fkey in mesh.faces(): if mesh.get_face_attribute(fkey, 'opening'): continue h_edges = mesh.face_halfedges(fkey) # arrange point lists in circular order along edge faces pts_coon = [] for h_edge in h_edges: pts = mesh.get_edge_attribute(h_edge, 'points')[:] if not h_edge in edges: pts.reverse() if not mesh.get_edge_attribute(h_edge, 'dir'): pts.reverse() pts_coon.append(pts) # handle triangles correctly based on user input (flag 0 - 2) if len(h_edges) == 4: ab, bc, dc, ad = pts_coon else: flag = mesh.get_face_attribute(fkey, 'corner') if flag == 0: ab, bc, dc, ad = pts_coon[0], pts_coon[1], [], pts_coon[2] elif flag == 1: ab, bc, dc, ad = pts_coon[0], [], pts_coon[1], pts_coon[2] elif flag == 2: ab, bc, dc, ad = pts_coon[0], pts_coon[1], pts_coon[2], [] # reverse for coons patch (see parameters) dc.reverse() ad.reverse() try: #this try except is a bit of a hack to make the openings work (needs revision) vertices, faces = discrete_coons_patch(ab, bc, dc, ad) coons_meshes.append(Mesh.from_vertices_and_faces(vertices, faces)) except: pass return coons_meshes
def to_radiating_mesh(self): # faces = self.radiating_faces() faces = [self.elements[fk].nodes for fk in self.radiating_faces()] # nodes = {nk for fk in faces for nk in self.elements[fk].nodes} # print(nodes) vertices = [self.nodes[k].xyz() for k in self.nodes] mesh = Mesh.from_vertices_and_faces(vertices, faces) mesh.cull_vertices() return mesh
def add_vertex_edge_for_load_support(network, sup_dic, load_dic, bars_len, key_removed_dic): """ Post-Processing Function: Adds vertices and edges in accordance with supports and loads returns the cured network """ if not key_removed_dic: load_sup_dic=merge_two_dicts(sup_dic, load_dic) else: load_dic_2=load_dic.copy() for key in key_removed_dic: load_dic_2.pop(key) load_dic_2=merge_two_dicts(load_dic_2, key_removed_dic[key]) load_sup_dic=merge_two_dicts(sup_dic, load_dic_2) # define arbitrary r to be added to get leaf vertex coordinates max_len=max(bars_len) r=max_len/3.0 # make a polygon and polyline from outer vertices of network points = network.to_points() cycles = network_find_cycles(network) mesh = Mesh.from_vertices_and_faces(points, cycles) if 0 in mesh.face and len(mesh.face)>1: mesh.delete_face(0) if len(mesh.face)==1: ver_lis=[key for key in mesh.vertices()] else: ver_lis=mesh.vertices_on_boundary(ordered=True) ver_lis_plyln=ver_lis[:] ver_lis_plyln.append(ver_lis[0]) pt_lis_plygn=[mesh.vertex_coordinates(key) for key in ver_lis] pt_lis_plyln=[mesh.vertex_coordinates(key) for key in ver_lis_plyln] plygn=Polygon(pt_lis_plygn) plyln=Polyline(pt_lis_plyln) # add leaf vertices for key in load_sup_dic: if load_sup_dic[key][0]!=0.0: pt_1=add_vectors(network.node_coordinates(key), (+r, 0.0, 0.0)) plyln_bln=is_point_on_polyline(pt_1, plyln.points, tol=0.001) plygn_bln=is_point_in_polygon_xy(pt_1, plygn.points) if plyln_bln or plygn_bln: pt_1=add_vectors(network.node_coordinates(key), (-r, 0.0, 0.0)) key_2=network.add_node(x=np.asscalar(pt_1[0]), y=pt_1[1], z=0.0) network.add_edge(key, key_2) if load_sup_dic[key][1]!=0.0: pt_2=add_vectors(network.node_coordinates(key), (0.0,+r, 0.0)) plyln_bln=is_point_on_polyline(pt_2, plyln.points, tol=0.001) plygn_bln=is_point_in_polygon_xy(pt_2, plygn.points) if plyln_bln or plygn_bln: pt_2=add_vectors(network.node_coordinates(key), (0.0,-r, 0.0)) key_2=network.add_node(x=pt_2[0], y=np.asscalar(pt_2[1]), z=0.0) network.add_edge(key, key_2) return network, plygn, plyln
def transform_part_geo(mesh_geo, T): mesh_data = mesh_geo.to_vertices_and_faces() t_mesh = Mesh.from_vertices_and_faces(mesh_data[0], mesh_data[1]) xyz = compas_geometry.transform_points_numpy(mesh_data[0], list(T)) for key, attr in t_mesh.vertices(True): attr['x'] = xyz[key][0] attr['y'] = xyz[key][1] attr['z'] = xyz[key][2] return t_mesh
def from_halfspaces(cls, halfspaces, interior_point): """Construct a polyhedron from its half-spaces and one interior point. Parameters ---------- halfspaces : array-like The coefficients of the hgalfspace equations in normal form. interior_point : array-like A point on the interior. Returns ------- :class:`compas.geometry.Polyhedron` Examples -------- >>> from compas.geometry import Plane >>> left = Plane([-1, 0, 0], [-1, 0, 0]) >>> right = Plane([+1, 0, 0], [+1, 0, 0]) >>> top = Plane([0, 0, +1], [0, 0, +1]) >>> bottom = Plane([0, 0, -1], [0, 0, -1]) >>> front = Plane([0, -1, 0], [0, -1, 0]) >>> back = Plane([0, +1, 0], [0, +1, 0]) >>> import numpy as np >>> halfspaces = np.array([left.abcd, right.abcd, top.abcd, bottom.abcd, front.abcd, back.abcd], dtype=float) >>> interior = np.array([0, 0, 0], dtype=float) >>> p = Polyhedron.from_halfspaces(halfspaces, interior) """ from itertools import combinations from numpy import asarray from scipy.spatial import HalfspaceIntersection, ConvexHull from compas.datastructures import Mesh, mesh_merge_faces from compas.geometry import length_vector, dot_vectors, cross_vectors halfspaces = asarray(halfspaces, dtype=float) interior_point = asarray(interior_point, dtype=float) hsi = HalfspaceIntersection(halfspaces, interior_point) hull = ConvexHull(hsi.intersections) mesh = Mesh.from_vertices_and_faces( [hsi.intersections[i] for i in hull.vertices], hull.simplices) mesh.unify_cycles() to_merge = [] for a, b in combinations(mesh.faces(), 2): na = mesh.face_normal(a) nb = mesh.face_normal(b) if dot_vectors(na, nb) >= 1: if length_vector(cross_vectors(na, nb)) < 1e-6: to_merge.append([a, b]) for faces in to_merge: mesh_merge_faces(mesh, faces) vertices, faces = mesh.to_vertices_and_faces() return cls(vertices, faces)
def get_halfedge_face(network): """ returns halfedge and face dictionary of the network """ points={key: network.node_coordinates(key) for key in network.nodes()} cycles=network_find_cycles(network, network.leaves()) mesh=Mesh.from_vertices_and_faces(points, cycles) dic_he=mesh.halfedge dic_fc=mesh.face return dic_he, dic_fc
def draw_uncut_mesh(self): """Computes and returns the beam geometry. Returns ------- compas.datastructures.Mesh The beam mesh without joint geoemtry """ box = Box(self.frame, self.length,self.width,self.height) box_mesh = Mesh.from_vertices_and_faces(box.vertices, box.faces) return box_mesh
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 mesh_quads(): vertices = [ [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0], [2.0, 0.0, 0.0], [2.0, 1.0, 0.0], ] faces = [[0, 1, 2, 3], [1, 4, 5, 2]] return Mesh.from_vertices_and_faces(vertices, faces)
def mesh_from_ansys_results(output_path, name): output_path = os.path.join(output_path, name + '_output') nodes, elements = get_nodes_elements_from_result_files(output_path) nkeys = sorted(nodes.keys(), key=int) vertices = [[nodes[k]['x'], nodes[k]['y'], nodes[k]['z']] for k in nkeys] fkeys = sorted(elements.keys(), key=int) faces = [] for fk in fkeys: face = elements[fk]['nodes'] face = face[:3] faces.append(face) mesh = Mesh.from_vertices_and_faces(vertices, faces) return mesh
def is_closed(self): """Verify that the polyhedron forms a closed surface. Returns ------- bool True if the polyhedron is closed. False otherwise. """ from compas.datastructures import Mesh mesh = Mesh.from_vertices_and_faces(self.vertices, self.faces) return mesh.is_closed()
def test_json_mesh(): before = Mesh.from_vertices_and_faces( [[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0]], [[0, 1, 2, 3]]) after = compas.json_loads(compas.json_dumps(before)) assert before.dtype == after.dtype assert all(before.has_vertex(vertex) for vertex in after.vertices()) assert all(after.has_vertex(vertex) for vertex in before.vertices()) assert all(before.has_face(face) for face in after.faces()) assert all(after.has_face(face) for face in before.faces()) assert all(before.has_edge(edge) for edge in after.edges()) assert all(after.has_edge(edge) for edge in before.edges()) assert all( before.face_vertices(a) == after.face_vertices(b) for a, b in zip(before.faces(), after.faces()))
def cell_to_mesh(self, cell): """Construct a mesh object from from a cell of a volmesh. Parameters ---------- cell : hashable Identifier of the cell. Returns ------- Mesh A mesh object. """ vertices, faces = self.cell_to_vertices_and_faces(cell) return Mesh.from_vertices_and_faces(vertices, faces)
def cell_to_mesh(self, cell): """Construct a mesh object from from a cell of a volmesh. Parameters ---------- cell : int Identifier of the cell. Returns ------- :class:`compas.datastructures.Mesh` A mesh object. """ vertices, faces = self.cell_to_vertices_and_faces(cell) return Mesh.from_vertices_and_faces(vertices, faces)
def from_vertices_and_faces(vs, fs): mesh = Mesh.from_vertices_and_faces(vs, fs) form = FormDiagram.from_mesh(mesh) corners = list(form.vertices_where({'vertex_degree': 2})) form.vertices_attribute('is_anchor', True, keys=corners) form.edges_attribute('q', 10.0, keys=form.edges_on_boundary()) relax_boundary_openings(form, corners) form.update_boundaries() force = ForceDiagram.from_formdiagram(form) horizontal_nodal(form, force, alpha=95) scale = vertical_from_zmax(form, 450.0) return form
def blocks(self): """Compute the blocks. Returns ------- list A list of blocks defined as simple meshes. Notes ----- This method is used by the ``from_geometry`` constructor of the assembly data structure to create an assembly "from geometry". """ if self.rise > self.span / 2: raise Exception("Not a semicircular arch.") radius = self.rise / 2 + self.span**2 / (8 * self.rise) # base = [0.0, 0.0, 0.0] top = [0.0, 0.0, self.rise] left = [-self.span / 2, 0.0, 0.0] center = [0.0, 0.0, self.rise - radius] vector = subtract_vectors(left, center) springing = angle_vectors(vector, [-1.0, 0.0, 0.0]) sector = radians(180) - 2 * springing angle = sector / self.n a = top b = add_vectors(top, [0, self.depth, 0]) c = add_vectors(top, [0, self.depth, self.thickness]) d = add_vectors(top, [0, 0, self.thickness]) R = Rotation.from_axis_and_angle([0, 1.0, 0], 0.5 * sector, center) bottom = transform_points([a, b, c, d], R) blocks = [] for i in range(self.n): R = Rotation.from_axis_and_angle([0, 1.0, 0], -angle, center) top = transform_points(bottom, R) vertices = bottom + top faces = [[0, 1, 2, 3], [7, 6, 5, 4], [3, 7, 4, 0], [6, 2, 1, 5], [7, 3, 2, 6], [5, 1, 0, 4]] mesh = Mesh.from_vertices_and_faces(vertices, faces) blocks.append(mesh) bottom = top return blocks
def to_tesselation(self): """Convert the surface to a triangle mesh. Returns ------- :class:`~compas.datastructures.Mesh` """ from OCC.Core.Tesselator import ShapeTesselator tess = ShapeTesselator(self.occ_shape) tess.Compute() vertices = [] triangles = [] for i in range(tess.ObjGetVertexCount()): vertices.append(tess.GetVertex(i)) for i in range(tess.ObjGetTriangleCount()): triangles.append(tess.GetTriangleIndex(i)) return Mesh.from_vertices_and_faces(vertices, triangles)
def to_tesselation(self) -> Mesh: """Create a tesselation of the shape for visualisation. Returns ------- :class:`~compas.datastructures.Mesh` """ tesselation = ShapeTesselator(self.shape) tesselation.Compute() vertices = [ tesselation.GetVertex(i) for i in range(tesselation.ObjGetVertexCount()) ] triangles = [ tesselation.GetTriangleIndex(i) for i in range(tesselation.ObjGetTriangleCount()) ] return Mesh.from_vertices_and_faces(vertices, triangles)
def hexagongrid(): polygon = Polygon.from_sides_and_radius_xy(6, 1) vertices = polygon.points vertices.append(polygon.centroid) x, y, z = zip(*vertices) xmin = min(x) xmax = max(x) ymin = min(y) ymax = max(y) faces = [[0, 1, 6], [1, 2, 6], [2, 3, 6], [3, 4, 6], [4, 5, 6], [5, 0, 6]] mesh = Mesh.from_vertices_and_faces(vertices, faces) meshes = [] for i in range(2): T = Translation.from_vector([i * (xmax - xmin), 0, 0]) meshes.append(mesh.transformed(T)) for i in range(2): T = Translation.from_vector([i * (xmax - xmin), ymax - ymin, 0]) meshes.append(mesh.transformed(T)) mesh = meshes_join_and_weld(meshes) return 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
def update_joint_mesh(self, BeamRef): """Compute the negative mesh volume of the joint. Returns ------- object A compas.Mesh Note ---- The self.mesh is updated with the new mesh """ TOLEARNCE = 10.0 # Get face_frame from Beam (the parent Beam) face_frame = BeamRef.face_frame(self.face_id) box_frame_origin = face_frame.represent_point_in_global_coordinates([ (self.distance - 50), TOLEARNCE * -1.0, TOLEARNCE * -1.0 ]) box_frame = Frame(box_frame_origin, face_frame.xaxis, face_frame.yaxis) # Compute 3 Box dimensions box_x = self.length box_y = self.width + TOLEARNCE box_z = self.height + 2 * TOLEARNCE # Draw Boolean Box boolean_box = Box(box_frame, box_x, box_y, box_z) boolean_box_mesh = Mesh.from_vertices_and_faces( boolean_box.vertices, boolean_box.faces) # Draw boolean box and assign to self.mesh self.mesh = boolean_box_mesh return self.mesh
# ============================================================================== # Main # ============================================================================== if __name__ == "__main__": from compas.datastructures import Mesh from compas.plotters import MeshPlotter vertices = [(0.0, 0.0, 0.0), (10.0, 0.0, 0.0), (10.0, 10.0, 0.0), (0.0, 10.0, 0.0), (5.0, 5.0, 0.0), (5.0, 5.0, 0.0)] faces = [[0, 1, 4], [1, 2, 4], [2, 3, 4], [3, 0, 5]] mesh = Mesh.from_vertices_and_faces(vertices, faces) plotter = MeshPlotter(mesh, figsize=(10, 7)) plotter.draw_edges(width=0.5) print("Original mesh:") print(mesh) mesh_cull_duplicate_vertices(mesh) print("Mesh with duplicate vertices deleted:") print(mesh) plotter.show()
from compas.datastructures import Mesh from compas.topology import trimesh_remesh from compas.topology import delaunay_from_points from compas.topology import voronoi_from_delaunay from compas.geometry import pointcloud_xy from compas.plotters import MeshPlotter points = pointcloud_xy(10, (0, 10)) faces = delaunay_from_points(points) delaunay = Mesh.from_vertices_and_faces(points, faces) trimesh_remesh(delaunay, 1.0, allow_boundary_split=True) points = [delaunay.vertex_coordinates(key) for key in delaunay.vertices()] faces = delaunay_from_points(points) delaunay = Mesh.from_vertices_and_faces(points, faces) voronoi = voronoi_from_delaunay(delaunay) lines = [] for u, v in voronoi.edges(): lines.append({ 'start': voronoi.vertex_coordinates(u, 'xy'), 'end': voronoi.vertex_coordinates(v, 'xy'), 'width': 1.0 }) plotter = MeshPlotter(delaunay, figsize=(10, 6))
right = Plane([+1, 0, 0], [+1, 0, 0]) top = Plane([0, 0, +1], [0, 0, +1]) bottom = Plane([0, 0, -1], [0, 0, -1]) front = Plane([0, -1, 0], [0, -1, 0]) back = Plane([0, +1, 0], [0, +1, 0]) halfspaces = array( [left.abcd, right.abcd, top.abcd, bottom.abcd, front.abcd, back.abcd], dtype=float) interior = array([0, 0, 0], dtype=float) hsi = HalfspaceIntersection(halfspaces, interior) hull = ConvexHull(hsi.intersections) mesh = Mesh.from_vertices_and_faces( [hsi.intersections[i] for i in hull.vertices], hull.simplices) mesh.unify_cycles() to_merge = [] for a, b in combinations(mesh.faces(), 2): na = Vector(*mesh.face_normal(a)) nb = Vector(*mesh.face_normal(b)) if na.dot(nb) >= 1: if na.cross(nb).length < 1e-6: to_merge.append([a, b]) for faces in to_merge: mesh.merge_faces(faces) viewer = App() viewer.add(mesh, show_vertices=True, pointsize=10)
a = Mesh.from_obj(igl.get('libigl-tutorial-data/cube.obj')) b = Mesh.from_obj(igl.get('libigl-tutorial-data/sphere.obj')) c = Mesh.from_obj(igl.get('libigl-tutorial-data/xcylinder.obj')) d = Mesh.from_obj(igl.get('libigl-tutorial-data/ycylinder.obj')) e = Mesh.from_obj(igl.get('libigl-tutorial-data/zcylinder.obj')) VA = numpy.array(a.get_vertices_attributes('xyz'), dtype=numpy.float64) FA = numpy.array([a.face_vertices(face) for face in a.faces()], dtype=numpy.int32) VB = numpy.array(b.get_vertices_attributes('xyz'), dtype=numpy.float64) FB = numpy.array([b.face_vertices(face) for face in b.faces()], dtype=numpy.int32) VC = numpy.array(c.get_vertices_attributes('xyz'), dtype=numpy.float64) FC = numpy.array([c.face_vertices(face) for face in c.faces()], dtype=numpy.int32) VD = numpy.array(d.get_vertices_attributes('xyz'), dtype=numpy.float64) FD = numpy.array([d.face_vertices(face) for face in d.faces()], dtype=numpy.int32) VE = numpy.array(e.get_vertices_attributes('xyz'), dtype=numpy.float64) FE = numpy.array([e.face_vertices(face) for face in e.faces()], dtype=numpy.int32) result = igl.mesh_csgtree(VA, FA, VB, FB, VC, FC, VD, FD, VE, FE) m = Mesh.from_vertices_and_faces(result.vertices, result.faces) viewer = MultiMeshViewer() viewer.meshes = [m] viewer.show()