예제 #1
0
def fix_mesh(mesh, resolution):
    bbox_min, bbox_max = mesh.bbox
    diag_len = norm(bbox_max - bbox_min)

    target_len = diag_len * resolution

    rospy.loginfo("\tTarget resolution: {} mm".format(target_len))

    count = 0
    mesh, __ = pymesh.remove_degenerated_triangles(mesh, 100)
    mesh, __ = pymesh.split_long_edges(mesh, target_len)
    num_vertices = mesh.num_vertices
    while True:
        mesh, __ = pymesh.collapse_short_edges(mesh, 1e-6)
        mesh, __ = pymesh.collapse_short_edges(mesh,
                                               target_len,
                                               preserve_feature=True)
        mesh, __ = pymesh.remove_obtuse_triangles(mesh, 150.0, 100)
        if mesh.num_vertices == num_vertices:
            break

        num_vertices = mesh.num_vertices
        rospy.loginfo("\t#vertices: {}".format(num_vertices))
        count += 1
        if count > 2: break

    mesh = pymesh.resolve_self_intersection(mesh)
    mesh, __ = pymesh.remove_duplicated_faces(mesh)
    mesh = pymesh.compute_outer_hull(mesh)
    mesh, __ = pymesh.remove_duplicated_faces(mesh)
    mesh, __ = pymesh.remove_obtuse_triangles(mesh, 179.0, 5)
    mesh, __ = pymesh.remove_isolated_vertices(mesh)

    return mesh
예제 #2
0
 def test_intersecting_cubes(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 = merge_meshes((mesh_1, mesh_2))
     outer_hull = compute_outer_hull(mesh)
     self.assertTrue(outer_hull.is_closed())
     self.assert_valid_attributes(mesh, outer_hull)
예제 #3
0
 def test_intersecting_cubes(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 = merge_meshes((mesh_1, mesh_2));
     outer_hull = compute_outer_hull(mesh);
     self.assertTrue(outer_hull.is_closed());
     self.assert_valid_attributes(mesh, outer_hull);
예제 #4
0
def fix_meshes(mesh, detail="normal"):
    meshCopy = mesh

    # copy/pasta of pymesh script fix_mesh from qnzhou, see pymesh on GitHub
    bbox_min, bbox_max = mesh.bbox
    diag_len = np.linalg.norm(bbox_max - bbox_min)
    if detail == "normal":
        target_len = diag_len * 5e-3
    elif detail == "high":
        target_len = diag_len * 2.5e-3
    elif detail == "low":
        target_len = diag_len * 1e-2

    count = 0
    mesh, __ = pymesh.remove_degenerated_triangles(mesh, 100)
    mesh, __ = pymesh.split_long_edges(mesh, target_len)
    num_vertices = mesh.num_vertices
    while True:
        mesh, __ = pymesh.collapse_short_edges(mesh, 1e-6)
        mesh, __ = pymesh.collapse_short_edges(mesh,
                                               target_len,
                                               preserve_feature=True)
        mesh, __ = pymesh.remove_obtuse_triangles(mesh, 150.0, 100)
        if mesh.num_vertices == num_vertices:
            break

        num_vertices = mesh.num_vertices
        count += 1
        if count > 10:
            break

    mesh = pymesh.resolve_self_intersection(mesh)
    mesh, __ = pymesh.remove_duplicated_faces(mesh)
    mesh = pymesh.compute_outer_hull(mesh)
    mesh, __ = pymesh.remove_duplicated_faces(mesh)
    mesh, __ = pymesh.remove_obtuse_triangles(mesh, 179.0, 5)
    mesh, __ = pymesh.remove_isolated_vertices(mesh)

    if is_mesh_broken(mesh, meshCopy) is True:
        if detail == "high":
            print(
                f'The function fix_meshes broke mesh, trying with lower details settings'
            )
            fix_meshes(mesh, detail="normal")
        if detail == "normal":
            print(
                f'The function fix_meshes broke mesh, trying with lower details settings'
            )
            fix_meshes(mesh, detail="low")
        if detail == "low":
            print(
                f'The function fix_meshes broke mesh, no lower settings can be applied, no fix was done'
            )
            return meshCopy
    else:
        return mesh
예제 #5
0
    def test_simple_cube(self):
        mesh = generate_box_mesh(np.array([0, 0, 0]), np.array([1, 1, 1]))
        outer_hulls = compute_outer_hull(mesh, all_layers=True)
        self.assertEqual(1, len(outer_hulls))
        outer_hull = outer_hulls[0]

        self.assertTrue(outer_hull.is_closed())
        self.assertEqual(mesh.num_vertices, outer_hull.num_vertices)
        self.assertEqual(mesh.num_faces, outer_hull.num_faces)
        self.assert_valid_attributes(mesh, outer_hull)
예제 #6
0
    def test_simple_cube(self):
        mesh = generate_box_mesh(
                np.array([0, 0, 0]), np.array([1, 1, 1]));
        outer_hulls = compute_outer_hull(mesh, all_layers=True);
        self.assertEqual(1, len(outer_hulls));
        outer_hull = outer_hulls[0];

        self.assertTrue(outer_hull.is_closed());
        self.assertEqual(mesh.num_vertices, outer_hull.num_vertices);
        self.assertEqual(mesh.num_faces, outer_hull.num_faces);
        self.assert_valid_attributes(mesh, outer_hull);
    def execute(self, context):
        scene = context.scene
        pymesh_props = scene.pymesh

        obj_a = context.active_object
        mesh_a = import_object(context, obj_a)
        pymesh_r = pymesh.compute_outer_hull(mesh_a)
        off_name = "Py.OH." + obj_a.name
        mesh_r = export_mesh(context, pymesh_r, off_name)
        add_to_scene(context, mesh_r)

        return {'FINISHED'}
예제 #8
0
    def test_multiple_components(self):
        mesh_1 = generate_box_mesh(np.array([0, 0, 0]), np.array([1, 1, 1]))
        mesh_2 = generate_box_mesh(np.array([2, 2, 2]), np.array([3, 3, 3]))

        mesh = merge_meshes((mesh_1, mesh_2))
        outer_hulls = compute_outer_hull(mesh, all_layers=True)
        self.assertEqual(1, len(outer_hulls))
        outer_hull = outer_hulls[0]

        self.assertTrue(outer_hull.is_closed())
        self.assertEqual(2, outer_hull.num_components)
        self.assert_valid_attributes(mesh, outer_hull)
예제 #9
0
def invert(src_file):

    src_path = os.path.join("/src", src_file)
    mesh = pymesh.meshio.load_mesh(src_path);
    mesh = pymesh.compute_outer_hull(mesh);

    print("model %s" % src_file)
    print(" vertices: %8s" % ("{:,}".format(mesh.num_vertices)))
    print("    faces: %8s" % ("{:,}".format(mesh.num_faces)))
    print("dimension: (%-.5f %-.5f %-.5f)" % (mesh.bbox[1][0] - mesh.bbox[0][0],
                                  mesh.bbox[1][1] - mesh.bbox[0][1], 
                                  mesh.bbox[1][2] - mesh.bbox[0][2]))
예제 #10
0
    def test_multiple_components(self):
        mesh_1 = generate_box_mesh(
                np.array([0, 0, 0]), np.array([1, 1, 1]));
        mesh_2 = generate_box_mesh(
                np.array([2, 2, 2]), np.array([3, 3, 3]));

        mesh = merge_meshes((mesh_1, mesh_2));
        outer_hulls = compute_outer_hull(mesh, all_layers=True);
        self.assertEqual(1, len(outer_hulls));
        outer_hull = outer_hulls[0];

        self.assertTrue(outer_hull.is_closed());
        self.assertEqual(2, outer_hull.num_components);
        self.assert_valid_attributes(mesh, outer_hull);
예제 #11
0
    def test_nested_cubes(self):
        mesh_1 = generate_box_mesh(np.array([0, 0, 0]), np.array([3, 3, 3]))
        mesh_2 = generate_box_mesh(np.array([1, 1, 1]), np.array([2, 2, 2]))

        mesh = merge_meshes((mesh_1, mesh_2))
        outer_hulls = compute_outer_hull(mesh, all_layers=True)
        self.assertEqual(2, len(outer_hulls))
        outer_hull = outer_hulls[0]
        interior_mesh = outer_hulls[1]

        self.assertTrue(outer_hull.is_closed())
        self.assertEqual(1, outer_hull.num_components)
        self.assert_valid_attributes(mesh, outer_hull)

        self.assertEqual(8, interior_mesh.num_vertices)
        self.assert_array_equal(([1, 1, 1], [2, 2, 2]), interior_mesh.bbox)
예제 #12
0
def fix_mesh(mesh):
    mesh, __ = pymesh.remove_degenerated_triangles(mesh, 100)
    log_mesh(mesh, "Remove degenerate faces")
    mesh, __ = pymesh.collapse_short_edges(mesh, MIN_RES, preserve_feature=True)
    log_mesh(mesh, "Collapse short edges")
    mesh = pymesh.resolve_self_intersection(mesh)
    mesh, __ = pymesh.remove_duplicated_faces(mesh)
    log_mesh(mesh, "Remove self intersections")
    mesh = pymesh.compute_outer_hull(mesh)
    mesh, __ = pymesh.remove_duplicated_faces(mesh)
    log_mesh(mesh, "New hull, remove duplicates")
    mesh, __ = pymesh.remove_obtuse_triangles(mesh, 179.5, 5)
    log_mesh(mesh, "Remote obtuse faces")
    mesh, __ = pymesh.remove_isolated_vertices(mesh)
    log_mesh(mesh, "Remove isolated vertices")
    return mesh
예제 #13
0
파일: mesh.py 프로젝트: zeta1999/ucmr
def fix_mesh(mesh, detail=5e-3):
    # "normal": 5e-3
    # "high":   2.5e-3
    # "low":    2e-2
    # "vlow":   2.5e-2
    bbox_min, bbox_max = mesh.bbox
    diag_len = np.linalg.norm(bbox_max - bbox_min)
    if detail is None:
        detail = 5e-3
    target_len = diag_len * detail
    print("Target resolution: {} mm".format(target_len))

    count = 0
    mesh, __ = pymesh.remove_degenerated_triangles(mesh, 100)
    mesh, __ = pymesh.split_long_edges(mesh, target_len)
    num_vertices = mesh.num_vertices
    while True:
        mesh, __ = pymesh.collapse_short_edges(mesh, 1e-4)
        mesh, __ = pymesh.collapse_short_edges(mesh,
                                               target_len,
                                               preserve_feature=True)

        mesh, __ = pymesh.remove_isolated_vertices(mesh)
        mesh, __ = pymesh.remove_duplicated_vertices(mesh, tol=1e-4)
        mesh, __ = pymesh.remove_duplicated_faces(mesh)
        mesh, __ = pymesh.remove_degenerated_triangles(mesh)
        mesh, __ = pymesh.remove_isolated_vertices(mesh)

        mesh, __ = pymesh.remove_obtuse_triangles(mesh, 150.0, 100)
        if mesh.num_vertices == num_vertices:
            break

        num_vertices = mesh.num_vertices
        print("fix #v: {}".format(num_vertices))
        count += 1
        if count > 10:
            break

    mesh = pymesh.resolve_self_intersection(mesh)
    mesh, __ = pymesh.remove_duplicated_faces(mesh)
    mesh = pymesh.compute_outer_hull(mesh)
    mesh, __ = pymesh.remove_duplicated_faces(mesh)
    mesh, __ = pymesh.remove_obtuse_triangles(mesh, 179.0, 5)
    mesh, __ = pymesh.remove_isolated_vertices(mesh)

    return mesh
예제 #14
0
def fix_mesh(mesh, detail="normal"):

    bbox_min, bbox_max = mesh.bbox
    diag_len = norm(bbox_max - bbox_min)

    if detail == "normal":
        target_len = diag_len * 1e-2

    elif detail == "high":
        target_len = diag_len * 5e-3

    elif detail == "low":
        target_len = diag_len * 0.03

    print("Target resolution: {} mm".format(target_len))

    count = 0
    mesh, __ = pymesh.remove_degenerated_triangles(mesh, 100)
    mesh, __ = pymesh.split_long_edges(mesh, target_len)
    num_vertices = mesh.num_vertices

    while True:
        mesh, __ = pymesh.collapse_short_edges(mesh, 1e-6)
        mesh, __ = pymesh.collapse_short_edges(mesh,
                                               target_len,
                                               preserve_feature=True)
        mesh, __ = pymesh.remove_obtuse_triangles(mesh, 150.0, 100)

        if mesh.num_vertices == num_vertices:
            break

        num_vertices = mesh.num_vertices
        print("#v: {}".format(num_vertices))
        count += 1
        if count > 10:
            break

    mesh = pymesh.resolve_self_intersection(mesh)
    mesh, __ = pymesh.remove_duplicated_faces(mesh)
    mesh = pymesh.compute_outer_hull(mesh)
    mesh, __ = pymesh.remove_duplicated_faces(mesh)
    mesh, __ = pymesh.remove_obtuse_triangles(mesh, 179.0, 5)
    mesh, __ = pymesh.remove_isolated_vertices(mesh)

    return mesh
예제 #15
0
def main():
    args = parse_args();
    mesh = pymesh.load_mesh(args.input_mesh);
    #mesh, __ = pymesh.remove_degenerated_triangles(mesh, 1000);
    #pymesh.save_mesh("cleaned.msh", mesh);

    result = pymesh.compute_outer_hull(mesh, engine=args.engine,
            all_layers=args.recursive);

    if args.recursive:
        basename, ext = os.path.splitext(args.output_mesh);
        for i,outer_hull in enumerate(result):
            out_name = "{}_{}{}".format(basename, i, ext);
            pymesh.save_mesh(out_name, outer_hull,
                    *outer_hull.get_attribute_names());
    else:
        pymesh.save_mesh(args.output_mesh, result,
                *result.get_attribute_names());
def fix_mesh(mesh, detail="normal"):
    bbox_min, bbox_max = mesh.bbox;
    diag_len = norm(bbox_max - bbox_min);
    if detail == "normal":
        target_len = diag_len * 1e-2;
        #target_len = diag_len * 5e-3;
    elif detail == "enormal":
        target_len = diag_len * 5e-3
    elif detail == "high":
        target_len = diag_len * 3e-3
        #target_len = diag_len * 2.5e-3;
    elif detail == "low":
        target_len = diag_len * 1e-2;
    elif detail == "ehigh":
        target_len = diag_len * 1e-3;
    print("Target resolution: {} mm".format(target_len));

    count = 0;
    mesh, __ = pymesh.remove_degenerated_triangles(mesh, 100);
    mesh, __ = pymesh.split_long_edges(mesh, target_len);
    num_vertices = mesh.num_vertices;
    while True:
        #mesh, __ = pymesh.collapse_short_edges(mesh, 1e-6);
        if detail == "low":
            mesh, __ = pymesh.collapse_short_edges(mesh, target_len, preserve_feature=False);
        else:
            mesh, __ = pymesh.collapse_short_edges(mesh, target_len, preserve_feature=True);
        mesh, __ = pymesh.remove_obtuse_triangles(mesh, 150.0, 100);
        if mesh.num_vertices == num_vertices:
            break;

        num_vertices = mesh.num_vertices;
        print("#v: {}".format(num_vertices));
        count += 1;
        if count > 10: break;

    mesh = pymesh.resolve_self_intersection(mesh);
    mesh, __ = pymesh.remove_duplicated_faces(mesh);
    mesh = pymesh.compute_outer_hull(mesh);
    mesh, __ = pymesh.remove_duplicated_faces(mesh);
    mesh, __ = pymesh.remove_obtuse_triangles(mesh, 179.0, 5);
    mesh, __ = pymesh.remove_isolated_vertices(mesh);

    return mesh;
예제 #17
0
    def test_nested_cubes(self):
        mesh_1 = generate_box_mesh(
                np.array([0, 0, 0]), np.array([3, 3, 3]));
        mesh_2 = generate_box_mesh(
                np.array([1, 1, 1]), np.array([2, 2, 2]));

        mesh = merge_meshes((mesh_1, mesh_2));
        outer_hulls = compute_outer_hull(mesh, all_layers=True);
        self.assertEqual(2, len(outer_hulls));
        outer_hull = outer_hulls[0];
        interior_mesh = outer_hulls[1];

        self.assertTrue(outer_hull.is_closed());
        self.assertEqual(1, outer_hull.num_components);
        self.assert_valid_attributes(mesh, outer_hull);

        self.assertEqual(8, interior_mesh.num_vertices);
        self.assert_array_equal(([1, 1, 1], [2, 2, 2]),
                interior_mesh.bbox);
예제 #18
0
def fix_mesh(mesh, target_len):
    bbox_min, bbox_max = mesh.bbox
    diag_len = np.linalg.norm(bbox_max - bbox_min)

    count = 0
    print("  remove degenerated triangles")
    mesh, __ = pymesh.remove_degenerated_triangles(mesh, 100)
    print("  split long edges")
    mesh, __ = pymesh.split_long_edges(mesh, target_len)
    num_vertices = mesh.num_vertices
    while True:
        print("  pass %d" % count)
        print("    collapse short edges #1")
        mesh, __ = pymesh.collapse_short_edges(mesh, 1e-6)
        print("    collapse short edges #2")
        mesh, __ = pymesh.collapse_short_edges(mesh,
                                               target_len,
                                               preserve_feature=True)
        print("    remove obtuse triangles")
        mesh, __ = pymesh.remove_obtuse_triangles(mesh, 150.0, 100)
        print("    %d of %s vertices." % (num_vertices, mesh.num_vertices))

        if mesh.num_vertices == num_vertices:
            break

        num_vertices = mesh.num_vertices
        count += 1
        if count > 10: break

    print("  resolve self intersection")
    mesh = pymesh.resolve_self_intersection(mesh)
    print("  remove duplicated faces")
    mesh, __ = pymesh.remove_duplicated_faces(mesh)
    print("  computer outer hull")
    mesh = pymesh.compute_outer_hull(mesh)
    print("  remove duplicated faces")
    mesh, __ = pymesh.remove_duplicated_faces(mesh)
    print("  remove obtuse triangles")
    mesh, __ = pymesh.remove_obtuse_triangles(mesh, 179.0, 5)
    print("  remove isolated vertices")
    mesh, __ = pymesh.remove_isolated_vertices(mesh)

    return mesh
예제 #19
0
def main():
    args = parse_args()
    mesh = pymesh.load_mesh(args.input_mesh)
    #mesh, __ = pymesh.remove_degenerated_triangles(mesh, 1000);
    #pymesh.save_mesh("cleaned.msh", mesh);

    result = pymesh.compute_outer_hull(mesh,
                                       engine=args.engine,
                                       all_layers=args.recursive)

    if args.recursive:
        basename, ext = os.path.splitext(args.output_mesh)
        for i, outer_hull in enumerate(result):
            out_name = "{}_{}{}".format(basename, i, ext)
            pymesh.save_mesh(out_name, outer_hull,
                             *outer_hull.get_attribute_names())
    else:
        pymesh.save_mesh(args.output_mesh, result,
                         *result.get_attribute_names())
예제 #20
0
def old_fix_mesh(vertices, faces, detail="normal"):
    bbox_min = np.amin(vertices, axis=0)
    bbox_max = np.amax(vertices, axis=0)
    diag_len = norm(bbox_max - bbox_min)
    if detail == "normal":
        target_len = diag_len * 5e-3
    elif detail == "high":
        target_len = diag_len * 2.5e-3
    elif detail == "low":
        target_len = diag_len * 1e-2
    print("Target resolution: {} mm".format(target_len))

    count = 0
    vertices, faces = pymesh.split_long_edges(vertices, faces, target_len)
    num_vertices = len(vertices)
    while True:
        vertices, faces = pymesh.collapse_short_edges(vertices, faces, 1e-6)
        vertices, faces = pymesh.collapse_short_edges(vertices,
                                                      faces,
                                                      target_len,
                                                      preserve_feature=True)
        vertices, faces = pymesh.remove_obtuse_triangles(
            vertices, faces, 150.0, 100)
        if num_vertices == len(vertices):
            break
        num_vertices = len(vertices)
        print("#v: {}".format(num_vertices))
        count += 1
        if count > 10: break

    vertices, faces = pymesh.resolve_self_intersection(vertices, faces)
    vertices, faces = pymesh.remove_duplicated_faces(vertices, faces)
    vertices, faces, _ = pymesh.compute_outer_hull(vertices, faces, False)
    vertices, faces = pymesh.remove_duplicated_faces(vertices, faces)
    vertices, faces = pymesh.remove_obtuse_triangles(vertices, faces, 179.0, 5)
    vertices, faces, voxels = pymesh.remove_isolated_vertices(vertices, faces)
    return vertices, faces
예제 #21
0
파일: fix_mesh.py 프로젝트: gaoyue17/PyMesh
def fix_mesh(mesh, detail="normal"):
    bbox_min, bbox_max = mesh.bbox;
    diag_len = norm(bbox_max - bbox_min);
    if detail == "normal":
        target_len = diag_len * 5e-3;
    elif detail == "high":
        target_len = diag_len * 2.5e-3;
    elif detail == "low":
        target_len = diag_len * 1e-2;
    print("Target resolution: {} mm".format(target_len));

    count = 0;
    mesh, __ = pymesh.remove_degenerated_triangles(mesh, 100);
    mesh, __ = pymesh.split_long_edges(mesh, target_len);
    num_vertices = mesh.num_vertices;
    while True:
        mesh, __ = pymesh.collapse_short_edges(mesh, 1e-6);
        mesh, __ = pymesh.collapse_short_edges(mesh, target_len,
                preserve_feature=True);
        mesh, __ = pymesh.remove_obtuse_triangles(mesh, 150.0, 100);
        if mesh.num_vertices == num_vertices:
            break;

        num_vertices = mesh.num_vertices;
        print("#v: {}".format(num_vertices));
        count += 1;
        if count > 10: break;

    mesh = pymesh.resolve_self_intersection(mesh);
    mesh, __ = pymesh.remove_duplicated_faces(mesh);
    mesh = pymesh.compute_outer_hull(mesh);
    mesh, __ = pymesh.remove_duplicated_faces(mesh);
    mesh, __ = pymesh.remove_obtuse_triangles(mesh, 179.0, 5);
    mesh, __ = pymesh.remove_isolated_vertices(mesh);

    return mesh;
예제 #22
0
def equalize_valences(mesh):
    edges = get_edges(mesh)
    for e in range(len(edges)):
        if e >= len(edges):
            break

        # if is_border(edges[e][0],mesh) and is_border(edges[e][1],mesh):
        #     continue

        v, _ = vertices_triangles_adjacent(e, edges, mesh)
        if len(v) != 4:
            continue

        print(e, end="\r")
        deviation_pre = deviation(v, mesh)
        new_mesh = flip_edge(e, edges, mesh)
        deviation_post = deviation(v, new_mesh)

        if deviation_pre > deviation_post:
            mesh = new_mesh
            edges = get_edges(mesh)

    mesh = pymesh.compute_outer_hull(mesh)
    return mesh
예제 #23
0
def compute_boundary_mesh(mesh):
    """Returns outer hull of input mesh"""
    return pymesh.compute_outer_hull(mesh)
예제 #24
0
    def pool(faceIndex,point,volume):
        found = False

        # Compute first z-value
        A = faceArea[faceIndex]
        h = volume/A
        Z = point[2]+h

        # Initialize face index, z-values and areas
        adjFace = [faceIndex, ]
        faceZ = [point[2],]
        faceA = [A,]

        # Find adjacent faces
        for faceIn in adjFace:

            for af in mesh.get_face_adjacent_faces(faceIn):

                # Get Z-value of face-centroid
                fc = faceCen[af][2]

                # Append them to list if their centroid is lower than the computed Z-value and are not already in list
                if fc < Z:
                    if af not in adjFace:

                        # If current face holds a volume add that volume to the current volume
                        if af in fI:
                            #print('found in fI')
                            queueIndex = fI.index(af)

                            if queueIndex in notDoneList:
                                #print('found in notDoneList')
                                volume += vols[queueIndex]
                                notDoneList.remove(queueIndex)
                                doneList.append(queueIndex)

                            elif queueIndex in doneList:
                                #print('found in doneList')
                                vols[queueIndex] += volume
                                notDoneList.append(queueIndex)
                                doneList.remove(queueIndex)
                                return

                            else:
                                pass

                        # Append Z-value, area and face-index
                        faceZ.append(fc)
                        faceA.append(faceArea[af])
                        adjFace.append(int(af))

                        # Convert to numpy array
                        faZ = array(faceZ)
                        faA = array(faceA)

                        # Compute new z-value
                        Z = (npsum(faZ*faA)+volume)/npsum(faA)

        #print('Approx Z:',Z)

        # Create approximate volume mesh
        apxVert = []
        apxFace = []
        iApxVert = 0

        for af in adjFace:
            iApxVert = len(apxVert)
            apxVert.append(vertices[faceVert[af][0]])
            apxVert.append(vertices[faceVert[af][1]])
            apxVert.append(vertices[faceVert[af][2]])
            apxFace.append([iApxVert, iApxVert + 1, iApxVert + 2])

        # Create boundary mesh
        apxVert = array(apxVert)
        apxFace = array(apxFace)
        apxMesh = pm.form_mesh(apxVert, apxFace)

        # Boundary Box
        maxmin = apxMesh.bbox
        x1, y1, z1 = maxmin[0]
        x2, y2, z2 = maxmin[1]*1.1  # Increase Bbox with 10%
        x1 = x1*0.9  # Decrease Bbox with 10%
        y1 = y1*0.9  # Decrease Bbox with 10%

        #print('apxMesh:',maxmin[0],'\n\t',maxmin[1])

        zMax = mesh.bbox[1][2]
        #print('zMax:',zMax)
        #pm.save_mesh('apxmesh.obj', apxMesh)

        # Findheight helper functions
        def createBbox(z):
            bVert = []
            bFace = []
            bVox = []

            # Add vertices
            bVert.append(array([x1, y1, z1]))  # 0
            bVert.append(array([x1, y2, z1]))  # 1
            bVert.append(array([x1, y2, z]))  # 2
            bVert.append(array([x1, y1, z]))  # 3

            bVert.append(array([x2, y2, z]))  # 4
            bVert.append(array([x2, y2, z1]))  # 5
            bVert.append(array([x2, y1, z1]))  # 6
            bVert.append(array([x2, y1, z]))  # 7

            # Add faces
            bFace.append([0, 1, 3])  # side 1
            bFace.append([1, 2, 3])  # side 1
            bFace.append([0, 3, 7])  # side 2
            bFace.append([0, 6, 7])  # side 2
            bFace.append([7, 6, 5])  # side 3
            bFace.append([5, 7, 4])  # side 3
            bFace.append([4, 5, 1])  # side 4
            bFace.append([4, 2, 1])  # side 4
            bFace.append([0, 1, 6])  # side 5
            bFace.append([1, 5, 6])  # side 5
            bFace.append([3, 7, 2])  # side 6
            bFace.append([2, 7, 4])  # side 6

            # Add voxels
            bVox.append([0, 2, 3, 7])
            bVox.append([0, 1, 2, 7])
            bVox.append([0, 1, 6, 7])
            bVox.append([2, 4, 5, 7])
            bVox.append([1, 2, 5, 6])
            bVox.append([2, 4, 6, 7])

            # Create boundary mesh
            bVert = array(bVert)
            bFace = array(bFace)
            bVox = array(bVox)
            bMesh = pm.form_mesh(bVert, bFace, bVox)
            #pm.save_mesh('bMesh.obj', bMesh)

            return bMesh

        def getVolMesh(newMesh, bottomFaces, z):

            # Prepare to create volume mesh
            newMeshVert = newMesh.vertices
            volVert = []
            volFace = []
            volVox = []

            # Create volume mesh from bottom part of mesh
            for f in bottomFaces:
                iVer = len(volVert)

                oldVerts = []
                newVerts = []
                for v in f:
                    oldVerts.append(newMeshVert[v])
                    newV = array([newMeshVert[v][0], newMeshVert[v][1], z])
                    newVerts.append(newV)

                # Append vertices
                volVert += oldVerts
                volVert += newVerts

                # Append faces
                volFace.append([iVer, iVer + 1, iVer + 2])
                volFace.append([iVer + 3, iVer + 4, iVer + 5])

                # Append voxels
                volVox.append([iVer, iVer + 1, iVer + 2, iVer + 3])
                volVox.append([iVer + 1, iVer + 3, iVer + 4, iVer + 5])
                volVox.append([iVer + 1, iVer + 2, iVer + 3, iVer + 5])

            # Create volume mesh
            volVert = array(volVert)
            volFace = array(volFace)
            volVox = array(volVox)
            volMesh = pm.form_mesh(volVert, volFace, volVox)

            return volMesh

        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

        # Volume function to solve
        def findHeight(z):
            #print('current z:',z)

            # Check if pools will overflow mesh
            if z > zMax:
                z = zMax

            # Create Bbox
            bMesh = createBbox(z)

            # Make intersection
            newMesh, bottomFaces, warning = intersectAndBottomFaces(bMesh, z)

            # Create volume mesh
            volMesh = getVolMesh(newMesh, bottomFaces, z)

            if z == zMax:
                return 0

            else:
                # Compute volume
                volMesh.add_attribute('voxel_volume')
                volVol = volMesh.get_attribute('voxel_volume')
                volVol = sum(list((map(abs, volVol))))

                #print('volume',volume)
                #print('volVol1',volVol)

                return volume - volVol

        # Get final height
        zFinal = newton(findHeight,Z)

        # Create final mesh
        def finalMesh(z):
            poolWarning = None

            # Check if pools will overflow mesh
            if z > zMax:
                z = zMax
                poolWarning = 'The pool have a greater volume than the mesh can contain. Pool set to fill entire mesh.'

            # Create Bbox
            bMesh = createBbox(z)

            # Make intersection
            newMesh, bottomFaces, boolWarning = intersectAndBottomFaces(bMesh, z)

            # Create volume mesh
            volMesh = getVolMesh(newMesh, bottomFaces, z)

            volMesh.add_attribute('voxel_volume')
            volVol = volMesh.get_attribute('voxel_volume')
            volVol = sum(list(map(abs, volVol)))

            # Clean up mesh
            volMesh, info = pm.remove_isolated_vertices(volMesh)
            #print('num vertex removed', info["num_vertex_removed"])
            volMesh, info = pm.remove_duplicated_faces(volMesh)

            return volMesh, volVol, poolWarning, poolWarning

        # Save final mesh
        #print('zFinal',zFinal,'type:',type(zFinal))
        finalMesh, finalVol, poolWarning, boolWarning = finalMesh(zFinal)
        meshName = "poolMesh_" + str(faceIndex) + ".obj"
        hullMesh = pm.compute_outer_hull(finalMesh)
        pm.save_mesh(meshName, hullMesh)

        print(' ')
        print('volume',"{0:.3f}".format(volume))
        print('computed volume',"{0:.3f}".format(finalVol))
        print('closed?',finalMesh.is_closed())
        print(' ')

        return meshName
예제 #25
0
def fix_meshes(mesh, detail="normal"):
    """
    A pipeline to optimise and fix mesh based on pymesh Mesh object.

    1. A box is created around the mesh.
    2. A target length is found based on diagonal of the mesh box.
    3. You can choose between 3 level of details, normal details settings seems to be a good compromise between
    final mesh size and sufficient number of vertices. It highly depends on your final goal.
    4. Remove degenerated triangles aka collinear triangles composed of 3 aligned points. The number of iterations is 5
    and should remove all degenerated triangles
    5. Remove isolated vertices, not connected to any faces or edges
    6. Remove self intersection edges and faces which is not realistic
    7. Remove duplicated faces
    8. The removing of duplicated faces can leave some vertices alone, we will removed them
    9. The calculation of outer hull volume is useful to be sure that the mesh is still ok
    10. Remove obtuse triangles > 179 who is not realistic and increase computation time
    11. We will remove potential duplicated faces again
    12. And duplicated vertices again
    13. Finally we will look if the mesh is broken or not. If yes we will try lower settings, if the lowest settings
    broke the mesh we will return the initial mesh. If not, we will return the optimised mesh.

    :param mesh: Pymesh Mesh object to optimise
    :param detail: string 'high', 'normal' or 'low' ('normal' as default), or float/int
    Settings to choose the targeting minimum length of edges
    :return: Pymesh Mesh object
    An optimised mesh or not depending on detail settings and mesh quality
    """
    meshCopy = mesh

    # copy/pasta of pymesh script fix_mesh from qnzhou, see pymesh on GitHub
    bbox_min, bbox_max = mesh.bbox
    diag_len = np.linalg.norm(bbox_max - bbox_min)
    if detail == "normal":
        target_len = diag_len * 5e-3
    elif detail == "high":
        target_len = diag_len * 2.5e-3
    elif detail == "low":
        target_len = diag_len * 1e-2
    elif detail is float or detail is int and detail > 0:
        target_len = diag_len * detail
    else:
        print(
            'Details settings is invalid, must be "low", "normal", "high" or positive int or float'
        )
        quit()

    count = 0
    mesh, __ = pymesh.remove_degenerated_triangles(mesh, 5)
    mesh, __ = pymesh.split_long_edges(mesh, target_len)
    num_vertices = mesh.num_vertices
    while True:
        mesh, __ = pymesh.collapse_short_edges(mesh,
                                               target_len,
                                               preserve_feature=True)
        mesh, info = pymesh.remove_obtuse_triangles(mesh, 179.0, 5)
        if mesh.num_vertices == num_vertices:
            break

        num_vertices = mesh.num_vertices
        count += 1
        if count > 10:
            break

    mesh, __ = pymesh.remove_duplicated_vertices(mesh)
    mesh, __ = pymesh.remove_isolated_vertices(mesh)
    mesh = pymesh.resolve_self_intersection(mesh)
    mesh, __ = pymesh.remove_duplicated_faces(mesh)
    mesh, __ = pymesh.remove_duplicated_vertices(mesh)
    mesh = pymesh.compute_outer_hull(mesh)
    mesh, __ = pymesh.remove_obtuse_triangles(mesh, 179.0, 5)
    mesh, __ = pymesh.remove_duplicated_faces(mesh)
    mesh, __ = pymesh.remove_isolated_vertices(mesh)

    if is_mesh_broken(mesh, meshCopy) is True:
        if detail == "high":
            print(
                f'The function fix_meshes broke mesh, trying with lower details settings'
            )
            fix_meshes(meshCopy, detail="normal")
            return mesh
        if detail == "normal":
            print(
                f'The function fix_meshes broke mesh, trying with lower details settings'
            )
            mesh = fix_meshes(meshCopy, detail="low")
            return mesh
        if detail == "low":
            print(
                f'The function fix_meshes broke mesh, no lower settings can be applied, no fix was done'
            )
            return meshCopy
    else:
        return mesh