def test_nested_mesh(self): mesh_1 = generate_box_mesh( np.array([0, 0, 0]), np.array([1, 1, 1])) mesh_2 = generate_box_mesh( np.array([-1, -1, -1]), np.array([2, 2, 2])) mesh = boolean(mesh_1, mesh_2, "intersection", "igl") self.assert_array_equal(mesh_1.bbox, mesh.bbox) mesh = boolean(mesh_1, mesh_2, "union", "igl") self.assert_array_equal(mesh_2.bbox, mesh.bbox) mesh = boolean(mesh_1, mesh_2, "difference", "igl") self.assertEqual(0, mesh.num_vertices) self.assertEqual(0, mesh.num_faces) mesh = boolean(mesh_2, mesh_1, "difference", "igl") self.assertEqual(16, mesh.num_vertices) self.assertEqual(24, mesh.num_faces) self.assert_array_equal(mesh_2.bbox, mesh.bbox) self.assertTrue(mesh.is_closed()) self.assertTrue(mesh.is_manifold()) self.assertEqual(2, mesh.num_components) mesh = boolean(mesh_1, mesh_2, "symmetric_difference", "igl") self.assertEqual(16, mesh.num_vertices) self.assertEqual(24, mesh.num_faces) self.assert_array_equal(mesh_2.bbox, mesh.bbox) self.assertTrue(mesh.is_closed()) self.assertTrue(mesh.is_manifold()) self.assertEqual(2, mesh.num_components)
def test_nested_mesh(self): mesh_1 = generate_box_mesh( np.array([0, 0, 0]), np.array([1, 1, 1])); mesh_2 = generate_box_mesh( np.array([-1, -1, -1]), np.array([2, 2, 2])); mesh = boolean(mesh_1, mesh_2, "intersection", "igl"); self.assert_array_equal(mesh_1.bbox, mesh.bbox); mesh = boolean(mesh_1, mesh_2, "union", "igl"); self.assert_array_equal(mesh_2.bbox, mesh.bbox); mesh = boolean(mesh_1, mesh_2, "difference", "igl"); self.assertEqual(0, mesh.num_vertices); self.assertEqual(0, mesh.num_faces); mesh = boolean(mesh_2, mesh_1, "difference", "igl"); self.assertEqual(16, mesh.num_vertices); self.assertEqual(24, mesh.num_faces); self.assert_array_equal(mesh_2.bbox, mesh.bbox); self.assertTrue(mesh.is_closed()); self.assertTrue(mesh.is_manifold()); self.assertEqual(2, mesh.num_components); mesh = boolean(mesh_1, mesh_2, "symmetric_difference", "igl"); self.assertEqual(16, mesh.num_vertices); self.assertEqual(24, mesh.num_faces); self.assert_array_equal(mesh_2.bbox, mesh.bbox); self.assertTrue(mesh.is_closed()); self.assertTrue(mesh.is_manifold()); self.assertEqual(2, mesh.num_components);
def commit_meshes(self): layers = list(self.per_layer_combinations.keys())[1:] for layer_index in layers: curr_layer = self.per_layer_combinations[layer_index] prev_layer = self.per_layer_combinations[layer_index - 1] for entry in curr_layer: if not entry.used: continue left_entry = prev_layer[entry.left_index] right_entry = prev_layer[entry.right_index] if entry.op == OpType.UNION: out_obj = pymesh.boolean(left_entry.obj, right_entry.obj, operation="union") elif entry.op == OpType.DIFF: out_obj = pymesh.boolean(left_entry.obj, right_entry.obj, operation="difference") elif entry.op == OpType.INTER: out_obj = pymesh.boolean( left_entry.obj, right_entry.obj, operation="intersection", ) elif entry.op == OpType.NONE: continue else: raise ValueError("Unknown operation: {}".format(entry.op)) entry.obj = out_obj
def test_simple_intersection(self): mesh_1 = generate_box_mesh(np.array([0, 0, 0]), np.array([2, 2, 2])) mesh_2 = generate_box_mesh(np.array([1, 1, 1]), np.array([3, 3, 3])) mesh = boolean(mesh_1, mesh_2, "intersection", "igl") self.assertEqual(8, mesh.num_vertices) self.assertEqual(12, mesh.num_faces) self.assertTrue(mesh.is_manifold()) self.assertTrue(mesh.is_closed()) self.assertEqual(1, mesh.num_components) mesh = boolean(mesh_1, mesh_2, "union", "igl") self.assertEqual(20, mesh.num_vertices) self.assertEqual(36, mesh.num_faces) self.assertTrue(mesh.is_manifold()) self.assertTrue(mesh.is_closed()) self.assertEqual(1, mesh.num_components) mesh = boolean(mesh_1, mesh_2, "difference", "igl") self.assertEqual(14, mesh.num_vertices) self.assertEqual(24, mesh.num_faces) self.assertTrue(mesh.is_manifold()) self.assertTrue(mesh.is_closed()) self.assertEqual(1, mesh.num_components) mesh = boolean(mesh_1, mesh_2, "symmetric_difference", "igl") self.assertEqual(22, mesh.num_vertices) self.assertEqual(48, mesh.num_faces) self.assertFalse(mesh.is_manifold()) self.assertTrue(mesh.is_closed()) self.assertEqual(1, mesh.num_components)
def bodyMaker(ratioF, frontD, ratioB, backD, ID, path): global body print("Making Side Mesh...") side = sideMesh(triangualtion(side1), 200) print("Fixing Side Mesh...") side = fixmesh.fix_mesh(side, detail="ehigh") print("Side Mesh Done") ##SIDE out pymesh.meshio.save_mesh("objs/side_%s.obj" % ID, side) print("Making Top Mesh...") top = topMesh(triangualtion(top1), 200) print("Fixing Top Mesh...") top = fixmesh.fix_mesh(top, detail="ehigh") print("Top Mesh Done") ##TOP out pymesh.meshio.save_mesh("objs/top_%s.obj" % ID, top) print("Making Front Mesh...") front = frontMesh(triangualtion(front1), frontD, ratioF) print("Fixing Front Mesh...") front = fixmesh.fix_mesh(front, detail="ehigh") print("Front Mesh Done") ##FRONT out pymesh.meshio.save_mesh("objs/front_%s.obj" % ID, front) print("Making Back Mesh...") back = backMesh(triangualtion(back1), backD, ratioB) print("Fixing Back Mesh...") back = fixmesh.fix_mesh(back, detail="ehigh") print("Back Mesh Done") ##BACK out pymesh.meshio.save_mesh("objs/back_%s.obj" % ID, back) print("Intersect between SIDE-TOP") sidetop = pymesh.boolean(side, top, operation="intersection", engine="igl") print("Fixing SIDE-TOP Mesh..") sidetop = fixmesh.fix_mesh(sidetop, detail="ehigh") pymesh.meshio.save_mesh("%ssidetop.obj" % path, sidetop) #pymesh.meshio.save_mesh("objs/sidetop_%s.obj"%ID, sidetop) print("Intersect between SIDE-TOP-FRONT") sidetopfront = pymesh.boolean(sidetop, front, operation="intersection", engine="igl") print("Fixing SIDE-TOP-FRONT Mesh..") sidetopfront = fixmesh.fix_mesh(sidetopfront, detail="ehigh") pymesh.meshio.save_mesh("objs/sidetopfront_%s.obj" % ID, sidetopfront) print("Intersect between SIDE-TOP-FRONT-BACK") sidetopfrontback = pymesh.boolean(sidetopfront, back, operation="intersection", engine="igl") print("Fixing SIDE-TOP-FRONT-BACK Mesh..") sidetopfrontback = fixmesh.fix_mesh(sidetopfrontback, detail="ehigh") body = sidetopfrontback print("ALL DONE.. Saving as 'body.obj'") pymesh.meshio.save_mesh("objs/body%s.obj" % ID, sidetopfrontback) pymesh.meshio.save_mesh("%sbody.obj" % path, sidetopfrontback)
def main(): args = parse_args(); mesh1 = pymesh.load_mesh(args.input_mesh_1); mesh2 = pymesh.load_mesh(args.input_mesh_2); if args.timing: mesh, t = pymesh.boolean(mesh1, mesh2, args.operation, args.engine, with_timing = args.timing, exact_mesh_file = args.exact); print("Timing: {}".format(t)); else: mesh = pymesh.boolean(mesh1, mesh2, args.operation, args.engine, exact_mesh_file = args.exact); pymesh.save_mesh(args.output_mesh, mesh, *mesh.get_attribute_names());
def test_cross_union(self): mesh_1 = generate_box_mesh(np.array([-2, -1, -1]), np.array([2, 1, 1])) mesh_2 = generate_box_mesh(np.array([-1, -2, -1]), np.array([1, 2, 1])) mesh_3 = generate_box_mesh(np.array([-1, -1, -2]), np.array([1, 1, 2])) mesh = boolean(mesh_1, mesh_2, "union", "igl") mesh = boolean(mesh, mesh_3, "union", "igl") self.assert_array_equal( np.array([[-2, -2, -2], [2, 2, 2]], dtype=float), mesh.bbox) self.assertTrue(mesh.is_closed()) self.assertTrue(mesh.is_manifold()) self.assertEqual(1, mesh.num_components)
def main(): args = parse_args() mesh = pymesh.load_mesh(args.input_mesh) if mesh.vertex_per_face == 4: logging.warning("Converting quad mesh to triangle mesh.") mesh = pymesh.quad_to_tri(mesh) if args.exact: name, ext = os.path.splitext(args.output_mesh) exact_mesh_file = name + ".xml" else: exact_mesh_file = None if mesh.num_vertices == 0 or mesh.num_faces == 0: # Empty input mesh, output empty mesh as well. result = pymesh.form_mesh(np.zeros((0, 3), dtype=float), np.zeros((0, 3), dtype=int)) if args.timing: update_info(args.output_mesh, 0) else: if args.engine == "igl": empty = pymesh.form_mesh(np.zeros((0, 3)), np.zeros((0, 3))) r = pymesh.boolean(mesh, empty, "union", engine=args.engine, with_timing=args.timing, exact_mesh_file=exact_mesh_file) else: # Empty mesh is valid for these libraries, using bbox instead. bbox = mesh.bbox center = (bbox[0] + bbox[1]) * 0.5 box = pymesh.generate_box_mesh(bbox[0] - np.ones(mesh.dim), bbox[1] + np.ones(mesh.dim)) r = pymesh.boolean(mesh, box, "intersection", engine=args.engine, with_timing=args.timing, exact_mesh_file=exact_mesh_file) if args.timing: result, timing = r update_info(args.output_mesh, timing) else: result = r pymesh.save_mesh(args.output_mesh, result)
def _shape_similarity(self, element1, element2): """ Similarity function that compares the bounding boxes of <element1> and <element2> Inputs: element1 (ProjectObject) element2 (ProjectObject) Return: float - bounding box IoU (Equation 1 in SUMO white paper) """ # quick intersection test. If bounding boxes don't overlap on any single axis, # then the enclosed object cannot overlap bbox1 = element1.posed_bbox bbox2 = element2.posed_bbox for axis in range(3): if (bbox1.min_corner[axis] > bbox2.max_corner[axis]) or \ (bbox2.min_corner[axis] > bbox1.max_corner[axis]): return 0 box1 = _bbox2pymesh(element1) box2 = _bbox2pymesh(element2) inter = pymesh.boolean(box1, box2, operation='intersection') ivert, ifaces, _ = remove_duplicated_vertices_raw( inter.vertices, inter.faces) inter_mesh = pymesh.form_mesh(ivert, ifaces) # Note: pymesh may give -volume depending on surface normals # or maybe vertex ordering intersection = abs(inter_mesh.volume) union = abs(box1.volume) + abs(box2.volume) - intersection return intersection / union
def test_intersection_with_self(self): mesh_1 = generate_box_mesh( np.array([0, 0, 0]), np.array([1, 1, 1])) mesh = boolean(mesh_1, mesh_1, "intersection", "igl") self.assertTrue(mesh.is_closed()) self.assertTrue(mesh.is_manifold()) self.assertTrue(1, mesh.num_components)
def carve_mesh(target_mesh, block, N, batch_size, out_name, initial_N=0, save_intermediate=True, debug=False): name, ext = os.path.splitext(out_name); tree = pymesh.AABBTree(); tree.load_mesh(target_mesh); dodecahedron = pymesh.generate_dodecahedron(1.0, np.zeros(3)); vertices = dodecahedron.vertices; faces = dodecahedron.faces; for i in range(initial_N, N, batch_size): pts = block.vertices; squared_dist, face_indices, closest_pts = \ tree.look_up_with_closest_points(pts); n = np.min([batch_size, N-i, len(pts)]); indices = np.argsort(squared_dist)[::-1][:n]; radii = np.sqrt(squared_dist[indices]); centers = pts[indices, :]; to_remove = [pymesh.form_mesh( np.dot(pymesh.Quaternion(numpy.random.rand(4)).to_matrix(), vertices.T * r).T + p, faces) for r,p in zip(radii, centers)]; to_remove = pymesh.merge_meshes(to_remove); if debug: pymesh.save_mesh("deubg_block.msh", block); pymesh.save_mesh("deubg_cut.msh", to_remove); block = pymesh.boolean(block, to_remove, "difference", engine="igl"); block, __ = pymesh.collapse_short_edges(block, 1e-12, False); if save_intermediate: pymesh.save_mesh("{}_{:06}{}".format(name, i, ext), block); return block;
def _shape_similarity(self, element1, element2): """ Similarity function that compares the bounding boxes of <element1> and <element2> Inputs: element1 (ProjectObject) element2 (ProjectObject) Return: float - bounding box IoU (Equation 1 in SUMO white paper) """ box1 = _bbox2pymesh(element1) box2 = _bbox2pymesh(element2) inter = pymesh.boolean(box1, box2, operation='intersection', engine='cgal') ivert, ifaces, _ = remove_duplicated_vertices_raw( inter.vertices, inter.faces) inter_mesh = pymesh.form_mesh(ivert, ifaces) # Note: pymesh may give -volume depending on surface normals # or maybe vertex ordering intersection = abs(inter_mesh.volume) union = abs(box1.volume) + abs(box2.volume) - intersection return intersection / union
def booleanOp(fv0, fv1, opstr, temppath): try: import pymesh except ImportError: print( "ERROR: CSG requires pymesh, which could not successfully be imported" ) print("returning first mesh only.") return fv0 else: file0 = os.path.join(temppath, 'file0.obj') file1 = os.path.join(temppath, 'file1.obj') writeFV(file0, fv0) writeFV(file1, fv1) mesh1 = pymesh.meshio.load_mesh(file0) if mesh1.vertex_per_face != 3: mesh1 = pymesh.quad_to_tri(mesh1) mesh2 = pymesh.meshio.load_mesh(file1) if mesh2.vertex_per_face != 3: mesh2 = pymesh.quad_to_tri(mesh2) meshout = pymesh.boolean(mesh1, mesh2, operation=opstr, engine='igl') # os.remove(file0) # os.remove(file1) return {'vertices': meshout.vertices, 'faces': meshout.faces}
def test_intersection_with_self(self): mesh_1 = generate_box_mesh( np.array([0, 0, 0]), np.array([1, 1, 1])); mesh = boolean(mesh_1, mesh_1, "intersection", "igl"); self.assertTrue(mesh.is_closed()); self.assertTrue(mesh.is_manifold()); self.assertTrue(1, mesh.num_components);
def trunk(ratioB, backD, path): #body = pymesh.load_mesh("objs/body_700_900_2.4.obj") back = backMesh(triangualtion(back3), backD, ratioB) back = fixmesh.fix_mesh(back, detail="ehigh") trunk = pymesh.boolean(back, body, operation="intersection", engine="igl") trunk = fixmesh.fix_mesh(trunk, detail="ehigh") print("front glass part is done.. Saving as 'trunk.obj'") pymesh.meshio.save_mesh("%strunk.obj" % path, trunk)
def main(): args = parse_args(); mesh = pymesh.load_mesh(args.input_mesh); if mesh.vertex_per_face == 4: logging.warning("Converting quad mesh to triangle mesh."); mesh = pymesh.quad_to_tri(mesh); if args.exact: name,ext = os.path.splitext(args.output_mesh); exact_mesh_file = name + ".xml"; else: exact_mesh_file = None; if mesh.num_vertices ==0 or mesh.num_faces == 0: # Empty input mesh, output empty mesh as well. result = pymesh.form_mesh(np.zeros((0,3),dtype=float), np.zeros((0,3),dtype=int)); if args.timing: update_info(args.output_mesh, 0); else: if args.engine == "igl": empty = pymesh.form_mesh(np.zeros((0,3)), np.zeros((0,3))); r = pymesh.boolean( mesh, empty, "union", engine=args.engine, with_timing = args.timing, exact_mesh_file=exact_mesh_file); else: # Empty mesh is valid for these libraries, using bbox instead. bbox = mesh.bbox; center = (bbox[0] + bbox[1]) * 0.5; box = pymesh.generate_box_mesh( bbox[0] - np.ones(mesh.dim), bbox[1] + np.ones(mesh.dim)); r = pymesh.boolean( mesh, box, "intersection", engine=args.engine, with_timing = args.timing, exact_mesh_file=exact_mesh_file); if args.timing: result, timing = r; update_info(args.output_mesh, timing); else: result = r; pymesh.save_mesh(args.output_mesh, result);
def test_cross_union(self): mesh_1 = generate_box_mesh( np.array([-2, -1, -1]), np.array([2, 1, 1])); mesh_2 = generate_box_mesh( np.array([-1, -2, -1]), np.array([1, 2, 1])); mesh_3 = generate_box_mesh( np.array([-1, -1, -2]), np.array([1, 1, 2])); mesh = boolean(mesh_1, mesh_2, "union", "igl"); mesh = boolean(mesh, mesh_3, "union", "igl"); self.assert_array_equal( np.array([[-2, -2, -2], [2, 2, 2]], dtype=float), mesh.bbox); self.assertTrue(mesh.is_closed()); self.assertTrue(mesh.is_manifold()); self.assertEqual(1, mesh.num_components);
def grill(ratioF, frontD, path): #body = pymesh.load_mesh("objs/body_700_900_2.4.obj") front = frontMesh(triangualtion(front5), frontD, ratioF) front = fixmesh.fix_mesh(front, detail="ehigh") Grill = pymesh.boolean(front, body, operation="intersection", engine="igl") Grill = fixmesh.fix_mesh(Grill, detail="ehigh") print("front glass part is done.. Saving as 'grill.obj'") #pymesh.meshio.save_mesh("objs/grill.obj", front) pymesh.meshio.save_mesh("%sgrill.obj" % path, Grill)
def generate_cuts(grains, n_grains, direction='x', levels=np.array([64]), zoom=4): """ Generate the cuts that can be plotted to image to be analyzed. """ # Column to be rescued, depends on direction if direction == 'x': cols = [0, 1, 2] elif direction == 'y': cols = [1, 0, 2] elif direction == 'z': cols = [2, 0, 1] results_per_level = [[None for i in range(n_grains)] for level in levels] # For each grain intersect with each of the different planes for i in range(n_grains): # Load grain from MATLAB output #g = load_grain(i) # Get vertices and faces (grain triangulation) #verts, faces = build_surface(g) verts, faces = grains[i] # Build high level mesh mesh = pymesh.form_mesh(verts, faces) # Iterate over planes for j, level in enumerate(levels): plane = build_plane(direction, level, 127) result = pymesh.boolean(mesh, plane, operation="intersection", engine="carve") if len(result.vertices) > 0: results_per_level[j][i] = result # Build cuts all_cuts = [None for results in results_per_level] for i, (level, results) in enumerate(zip(levels, results_per_level)): finals = [] # Filter results, some Nones are just non intersecting grains # The result is only PyMesh.Mesh objects results = [r for r in results if r is not None] # a single cut over a level is the union of each PyMesh.Mesh objects for r in results: mask = r.vertices[:, cols[0]] == level tmp = r.vertices[mask] finals.append(tmp[:, [cols[1], cols[2]]]) finals = np.vstack(finals) # Amplify image by a factor given by zoom finals = (finals * zoom).astype(int) # Binarize output M = np.zeros((np.max(finals) + 1, np.max(finals) + 1)) M[finals[:, 1], finals[:, 0]] = 1 # Dilate and skeletonize dit = morphology.binary_dilation(M, selem=np.ones((4, 4))) skt = morphology.skeletonize(dit) all_cuts[i] = skt return all_cuts
def sideGlass(path): #body = pymesh.load_mesh("objs/body_700_900_2.4.obj") side = sideMesh(triangualtion(side2), 200) side = fixmesh.fix_mesh(side, detail="ehigh") sideGlass = pymesh.boolean(side, body, operation="intersection", engine="igl") sideGlass = fixmesh.fix_mesh(sideGlass, detail="ehigh") print("front glass part is done.. Saving as 'sideGlass.obj'") pymesh.meshio.save_mesh("%ssideGlass.obj" % path, sideGlass)
def headLight(ratioF, frontD, path): #body = pymesh.load_mesh("objs/body_700_900_2.4.obj") front = frontMesh(triangualtion(front4), frontD, ratioF) front = fixmesh.fix_mesh(front, detail="ehigh") headLight = pymesh.boolean(front, body, operation="intersection", engine="igl") headLight = fixmesh.fix_mesh(headLight, detail="ehigh") print("front glass part is done.. Saving as 'headLight.obj'") pymesh.meshio.save_mesh("%sheadLight.obj" % path, headLight)
def frontBumper(ratioF, frontD, path): #body = pymesh.load_mesh("objs/body_700_900_2.4.obj") front = frontMesh(triangualtion(front9), frontD, ratioF) front = fixmesh.fix_mesh(front, detail="ehigh") frontBumper = pymesh.boolean(front, body, operation="intersection", engine="igl") frontBumper = fixmesh.fix_mesh(frontBumper, detail="ehigh") print("front glass part is done.. Saving as 'frontBumper.obj'") pymesh.meshio.save_mesh("%sfrontBumper.obj" % path, frontBumper)
def frontGlass(path): #body = pymesh.load_mesh("objs/body_700_900_2.4.obj") top = topMesh(triangualtion(top2), 200) top = fixmesh.fix_mesh(top, detail="ehigh") frontGlass = pymesh.boolean(top, body, operation="intersection", engine="igl") frontGlass = fixmesh.fix_mesh(frontGlass, detail="ehigh") print("front glass part is done.. Saving as 'frontGlass.obj'") pymesh.meshio.save_mesh("%sfrontGlass.obj" % path, frontGlass)
def test_intersection_with_slighly_rotated_self(self): mesh_1 = generate_box_mesh(np.array([0, 0, 0]), np.array([1, 1, 1])) rot = Quaternion.fromAxisAngle(np.array([1.0, 1.0, 1.0]), 0.0001) mesh_2 = form_mesh( np.dot(rot.to_matrix(), mesh_1.vertices.T).T, mesh_1.faces) mesh = boolean(mesh_1, mesh_2, "intersection", "igl") self.assertTrue(mesh.is_closed()) self.assertTrue(mesh.is_manifold()) self.assertTrue(1, mesh.num_components)
def test_rotation_180(self): mesh_1 = generate_box_mesh(np.array([-2, -1, -1]), np.array([2, 1, 1])) rot = Quaternion.fromAxisAngle(np.array([1.0, 1.0, 0.0]), math.pi / 2.0) mesh_2 = form_mesh( np.dot(rot.to_matrix(), mesh_1.vertices.T).T, mesh_1.faces) mesh = boolean(mesh_1, mesh_2, "union", "cgal") self.assertTrue(mesh.is_closed()) self.assertTrue(mesh.is_manifold()) self.assertEqual(1, mesh.num_components)
def test_face_face_touch_with_different_area(self): mesh_1 = generate_box_mesh(np.array([0, 0, 0]), np.array([1, 1, 1])) mesh_2 = generate_box_mesh(np.array([-1, -1, 1]), np.array([2, 2, 2])) mesh = boolean(mesh_1, mesh_2, "intersection", "igl") self.assertEqual(0, mesh.num_vertices) self.assertEqual(0, mesh.num_faces) self.assertTrue(mesh.is_manifold()) self.assertTrue(mesh.is_closed()) self.assertEqual(0, mesh.num_components)
def test_simple_intersection(self): mesh_1 = generate_box_mesh( np.array([0, 0, 0]), np.array([2, 2, 2])); mesh_2 = generate_box_mesh( np.array([1, 1, 1]), np.array([3, 3, 3])); mesh = boolean( mesh_1, mesh_2, "intersection", "igl"); self.assertEqual(8, mesh.num_vertices); self.assertEqual(12, mesh.num_faces); self.assertTrue(mesh.is_manifold()); self.assertTrue(mesh.is_closed()); self.assertEqual(1, mesh.num_components); mesh = boolean( mesh_1, mesh_2, "union", "igl"); self.assertEqual(20, mesh.num_vertices); self.assertEqual(36, mesh.num_faces); self.assertTrue(mesh.is_manifold()); self.assertTrue(mesh.is_closed()); self.assertEqual(1, mesh.num_components); mesh = boolean( mesh_1, mesh_2, "difference", "igl"); self.assertEqual(14, mesh.num_vertices); self.assertEqual(24, mesh.num_faces); self.assertTrue(mesh.is_manifold()); self.assertTrue(mesh.is_closed()); self.assertEqual(1, mesh.num_components); mesh = boolean( mesh_1, mesh_2, "symmetric_difference", "igl"); self.assertEqual(22, mesh.num_vertices); self.assertEqual(48, mesh.num_faces); self.assertFalse(mesh.is_manifold()); self.assertTrue(mesh.is_closed()); self.assertEqual(1, mesh.num_components);
def intersectAndBottomFaces(bMesh, z): warning = None # Make intersection with auto boolean engine newMesh = pm.boolean(mesh, bMesh, 'intersection') if newMesh.num_faces == 0: # Change boolean engine to Cork warning = 'Changing Boolean Engine to Cork!' print(warning) newMesh = pm.boolean(bMesh, mesh, 'difference', engine='cork') #pm.save_mesh('intMesh.obj', newMesh) # Get bottom part of mesh try: newSource = newMesh.get_attribute('source') newFace = newMesh.faces bottomFaces = [] for i, s in enumerate(newSource): if int(s) == 1: bottomFaces.append(newFace[i]) return newMesh, bottomFaces, warning except RuntimeError: # Try different approach to getting bottom faces newMesh.add_attribute('face_centroid') newFace = newMesh.faces # print('len newFace:',len(newFace)) # print('first newFace:',newFace[0]) newCen = newMesh.get_attribute('face_centroid') bottomFaces = [] for newFaceIndex in range(len(newFace)): newCenZ = newCen[newFaceIndex * 3 + 2] if newCenZ < z: bottomFaces.append(newFace[newFaceIndex]) return newMesh, bottomFaces, warning
def test_eps_corner_intersection(self): eps = np.finfo(np.float64).eps mesh_1 = generate_box_mesh(np.array([0, 0, 0]), np.array([1, 1, 1])) mesh_2 = generate_box_mesh( np.array([1, 1, 1]) - eps, np.array([3, 3, 3])) mesh = boolean(mesh_1, mesh_2, "intersection", "igl") self.assertEqual(8, mesh.num_vertices) self.assertEqual(12, mesh.num_faces) self.assertTrue(mesh.is_manifold()) self.assertTrue(mesh.is_closed()) self.assertEqual(1, mesh.num_components)
def test_rotate_union_120_degrees(self): # TODO: Bug mesh_1 = generate_box_mesh(np.array([-2, -1, -1]), np.array([2, 1, 1])) rot = Quaternion.fromAxisAngle(np.array([1.0, 0.0, 0.0]), float(2 * math.pi) / 3) mesh_2 = form_mesh( np.dot(rot.to_matrix(), mesh_1.vertices.T).T, mesh_1.faces) mesh = boolean(mesh_1, mesh_2, "union", "igl") self.assertTrue(mesh.is_closed()) self.assertTrue(mesh.is_manifold()) self.assertEqual(1, mesh.num_components)
def test_edge_edge_touch(self): mesh_1 = generate_box_mesh( np.array([0, 0, 0]), np.array([1, 1, 1])); mesh_2 = generate_box_mesh( np.array([0, 1, 1]), np.array([1, 2, 2])); mesh = boolean( mesh_1, mesh_2, "intersection", "igl"); self.assertEqual(0, mesh.num_vertices); self.assertEqual(0, mesh.num_faces); self.assertTrue(mesh.is_manifold()); self.assertTrue(mesh.is_closed()); self.assertEqual(0, mesh.num_components); mesh = boolean( mesh_1, mesh_2, "union", "igl"); self.assertEqual(14, mesh.num_vertices); self.assertEqual(24, mesh.num_faces); self.assertFalse(mesh.is_manifold()); self.assertTrue(mesh.is_closed()); self.assertEqual(1, mesh.num_components); mesh = boolean( mesh_1, mesh_2, "difference", "igl"); self.assert_array_equal(mesh_1.bbox, mesh.bbox); self.assertTrue(mesh.is_manifold()); self.assertTrue(mesh.is_closed()); self.assertEqual(1, mesh.num_components); mesh = boolean( mesh_1, mesh_2, "symmetric_difference", "igl"); self.assertEqual(14, mesh.num_vertices); self.assertEqual(24, mesh.num_faces); self.assertFalse(mesh.is_manifold()); self.assertTrue(mesh.is_closed()); self.assertEqual(1, mesh.num_components);
def supports(self, c): other = pymesh.form_mesh( c.component_mesh.vertices - numpy.array([0, 0, (c.z - self.z)]), c.component_mesh.faces) pymesh.remove_duplicated_vertices(other) pymesh.remove_duplicated_faces(other) intersection = pymesh.boolean(self.component_mesh, other, 'intersection') pymesh.remove_duplicated_vertices(intersection) pymesh.remove_duplicated_faces(intersection) intersection.add_attribute("face_area") intersection_area = sum(intersection.get_attribute("face_area")) return intersection_area >= 0.2 * self.area()
def test_eps_face_intersection(self): eps = np.finfo(np.float64).eps mesh_1 = generate_box_mesh(np.array([0, 0, 0]), np.array([1, 1, 1])) mesh_2 = generate_box_mesh(np.array([0, 0, 1 - eps]), np.array([1, 1, 2])) mesh = boolean(mesh_1, mesh_2, "intersection", "igl") bbox = mesh.bbox self.assert_array_equal(np.array([0, 0, 1 - eps]), bbox[0]) self.assert_array_equal(np.array([1, 1, 1]), bbox[1]) self.assertTrue(mesh.is_manifold()) self.assertTrue(mesh.is_closed()) self.assertEqual(1, mesh.num_components)
def test_rotation_180(self): mesh_1 = generate_box_mesh( np.array([-2, -1, -1]), np.array([2, 1, 1])); rot = Quaternion.fromAxisAngle( np.array([1.0, 1.0, 0.0]), math.pi / 2.0); mesh_2 = form_mesh( np.dot(rot.to_matrix(), mesh_1.vertices.T).T, mesh_1.faces); mesh = boolean(mesh_1, mesh_2, "union", "cgal"); self.assertTrue(mesh.is_closed()); self.assertTrue(mesh.is_manifold()); self.assertEqual(1, mesh.num_components);
def test_union_with_45_rotated_self(self): mesh_1 = generate_box_mesh( np.array([0, 0, 0]), np.array([1, 1, 1])); rot = Quaternion.fromAxisAngle(np.array([1.0, 1.0, 1.0]), math.pi/4.0); mesh_2 = form_mesh( np.dot(rot.to_matrix(), mesh_1.vertices.T).T, mesh_1.faces); mesh = boolean(mesh_1, mesh_2, "union", "igl"); self.assertTrue(mesh.is_closed()); self.assertTrue(mesh.is_manifold()); self.assertTrue(1, mesh.num_components);
def clip_polygon(polygons, vertices_hole, junctions, meta): """ clip polygon the hole """ if len(polygons) == 1: junctions = [junctions[vertex] for vertex in polygons[0]] mesh_wall = triangulate(junctions) vertices = np.array(mesh_wall.vertices) faces = np.array(mesh_wall.faces) return vertices, faces else: wall = [] holes = [] for polygon in polygons: if np.any(np.intersect1d(polygon, vertices_hole)): holes.append(polygon) else: wall.append(polygon) # extract junctions on this plane indices = [] junctions_wall = [] for plane in wall: for vertex in plane: indices.append(vertex) junctions_wall.append(junctions[vertex]) junctions_holes = [] for plane in holes: junctions_hole = [] for vertex in plane: indices.append(vertex) junctions_hole.append(junctions[vertex]) junctions_holes.append(junctions_hole) junctions_wall = [project(x, meta) for x in junctions_wall] junctions_holes = [[project(x, meta) for x in junctions_hole] for junctions_hole in junctions_holes] mesh_wall = triangulate(junctions_wall) for hole in junctions_holes: mesh_hole = triangulate(hole) mesh_wall = pymesh.boolean(mesh_wall, mesh_hole, 'difference') vertices = [project_inv(vertex, meta) for vertex in mesh_wall.vertices] return vertices, np.array(mesh_wall.faces)
def test_rotate_union_120_degrees(self): # TODO: Bug mesh_1 = generate_box_mesh( np.array([-2, -1, -1]), np.array([2, 1, 1])); rot = Quaternion.fromAxisAngle( np.array([1.0, 0.0, 0.0]), float(2*math.pi) / 3); mesh_2 = form_mesh( np.dot(rot.to_matrix(), mesh_1.vertices.T).T, mesh_1.faces); mesh = boolean(mesh_1, mesh_2, "union", "igl"); self.assertTrue(mesh.is_closed()); self.assertTrue(mesh.is_manifold()); self.assertEqual(1, mesh.num_components);
def test_eps_corner_intersection(self): eps = np.finfo(np.float64).eps; mesh_1 = generate_box_mesh( np.array([0, 0, 0]), np.array([1, 1, 1])); mesh_2 = generate_box_mesh( np.array([1, 1, 1]) - eps, np.array([3, 3, 3])); mesh = boolean( mesh_1, mesh_2, "intersection", "igl"); self.assertEqual(8, mesh.num_vertices); self.assertEqual(12, mesh.num_faces); self.assertTrue(mesh.is_manifold()); self.assertTrue(mesh.is_closed()); self.assertEqual(1, mesh.num_components);
def tryMerge(f1, f2, index): merged = "" if f1 == "" and f2 == "" : merged = "" if f1 == "" : merged = f2 if f2 == "" : merged = f1 else: start = time.time() merged = pymesh.boolean(f1, f2, operation="union") print("\tmerged in %f" % (time.time() - start)) meshBuffer[index] = merged readyMutex[index] = 1
def test_face_face_touch_with_different_area(self): mesh_1 = generate_box_mesh( np.array([0, 0, 0]), np.array([1, 1, 1])); mesh_2 = generate_box_mesh( np.array([-1, -1, 1]), np.array([2, 2, 2])); mesh = boolean( mesh_1, mesh_2, "intersection", "igl"); self.assertEqual(0, mesh.num_vertices); self.assertEqual(0, mesh.num_faces); self.assertTrue(mesh.is_manifold()); self.assertTrue(mesh.is_closed()); self.assertEqual(0, mesh.num_components);
def test_eps_face_intersection(self): eps = np.finfo(np.float64).eps; mesh_1 = generate_box_mesh( np.array([0, 0, 0]), np.array([1, 1, 1])); mesh_2 = generate_box_mesh( np.array([0, 0, 1-eps]), np.array([1, 1, 2])); mesh = boolean( mesh_1, mesh_2, "intersection", "igl"); bbox = mesh.bbox; self.assert_array_equal(np.array([0, 0, 1-eps]), bbox[0]); self.assert_array_equal(np.array([1, 1, 1]), bbox[1]); self.assertTrue(mesh.is_manifold()); self.assertTrue(mesh.is_closed()); self.assertEqual(1, mesh.num_components);
def slice_mesh(mesh, N): bbox_min, bbox_max = mesh.bbox; min_corner = [bbox_min[0] -1.0, bbox_min[1] - 1.0, bbox_min[2] - 1.0]; output_wires = []; for i in range(N): ratio = float(i) / float(N); slice_val = bbox_min[0] * ratio + bbox_max[0] * (1-ratio); max_corner = [slice_val, bbox_max[1] + 1.0, bbox_max[2] + 1.0]; box = pymesh.generate_box_mesh(min_corner, max_corner); diff = pymesh.boolean(box, mesh, "difference"); #pymesh.save_mesh("tmp_{}.msh".format(i), diff); vertices = diff.vertices; y_out_range = np.logical_or( vertices[:,1] < bbox_min[1], vertices[:,1] > bbox_max[1]); z_out_range = np.logical_or( vertices[:,2] < bbox_min[2], vertices[:,2] > bbox_max[2]); on_outside = np.logical_or(y_out_range, z_out_range); if not np.any(on_outside): continue; edges = []; for f in diff.faces: if np.sum(on_outside[f]) == 1: if on_outside[f[0]]: edges.append([f[1], f[2]]); if on_outside[f[1]]: edges.append([f[2], f[0]]); if on_outside[f[2]]: edges.append([f[0], f[1]]); if len(edges) == 0: continue; edges = np.array(edges, dtype=int); below_ground = vertices[:,1] < 0.5*(bbox_min[1]+bbox_max[1]); edges_below_ground = np.any(below_ground[edges], axis=1); edges = edges[np.logical_not(edges_below_ground)]; vertices, edges, __ = \ pymesh.remove_isolated_vertices_raw(vertices, edges); wires = pymesh.wires.WireNetwork.create_from_data(vertices, edges); output_wires.append(wires); print('.',end="",flush=True) print("done"); return output_wires;
def test_union_with_rotated_self(self): #TODO: bug mesh_1 = generate_box_mesh( np.array([0, 0, 0]), np.array([1, 1, 1])); rot = Quaternion.fromAxisAngle(np.array([1, 1, 0], dtype=float), math.pi * 0.5); mesh_2 = form_mesh( np.dot(rot.to_matrix(), mesh_1.vertices.T).T + np.array([0.5, 0.5, 0.5]), mesh_1.faces); mesh = boolean(mesh_1, mesh_2, "union", "igl"); self.assertTrue(mesh.is_closed()); self.assertTrue(mesh.is_manifold()); self.assertEqual(1, mesh.num_components);
def test_edge_edge_orthogonal_touch(self): eps = np.finfo(float).eps; mesh_1 = generate_box_mesh( np.array([0, 0, 0]), np.array([1, 1, 1])); rot = Quaternion.fromAxisAngle(np.array([1, 1, 0], dtype=float), math.pi * 0.5); mesh_2 = form_mesh( np.dot(rot.to_matrix(), mesh_1.vertices.T).T + np.array([-1, -1, 0.5], dtype=float)+ np.array([-math.sqrt(2)/4.0 + eps, math.sqrt(2)/4.0+eps, 0.0], dtype=float), mesh_1.faces); mesh = boolean(mesh_1, mesh_2, "union", "igl"); self.assertTrue(mesh.is_closed()); self.assertTrue(mesh.is_manifold()); self.assertEqual(1, mesh.num_components);
def test_rotation_union_stress_2(self): # TODO: Bug N = 3; mesh_1 = generate_box_mesh( np.array([-2, -1, -1]), np.array([2, 1, 1])); mesh = mesh_1; for i in range(N): rot = Quaternion.fromAxisAngle( np.array([1.0, 1.0, 0.0]), float(i*2*math.pi) / N); mesh_2 = form_mesh( np.dot(rot.to_matrix(), mesh_1.vertices.T).T, mesh_1.faces); mesh = boolean(mesh, mesh_2, "union", "igl"); self.assertTrue(mesh.is_closed()); self.assertTrue(mesh.is_manifold()); self.assertEqual(1, mesh.num_components);
def test_face_edge_touch(self): mesh_1 = generate_box_mesh( np.array([0, 0, 0]), np.array([1, 1, 1])); rot = Quaternion.fromData( np.array([1, 0, 1], dtype=float), np.array([0, 0, 1], dtype=float)); mesh_2 = form_mesh( np.dot(rot.to_matrix(), mesh_1.vertices.T).T + np.array([0.5, 0.5, 1.0]), mesh_1.faces); mesh = boolean(mesh_1, mesh_2, "union", "igl"); self.assertEqual(17, mesh.num_vertices); self.assertEqual(30, mesh.num_faces); self.assertFalse(mesh.is_manifold()); self.assertTrue(mesh.is_closed()); self.assertEqual(1, mesh.num_components);