<jupyter_start><jupyter_text>Step 1:<jupyter_code>Lw = igl.cotmatrix(v, f)
M = igl.massmatrix(v, f, igl.MASSMATRIX_TYPE_BARYCENTRIC)
M_inverse = sp.diags(1 / M.data)

A = Lw @ M_inverse @ Lw
Aff = A[labels==0, :][:, labels==0]
Afc = A[labels==0, :][:, labels>0]

if option == 2 or option == 3:
    c, low = cho_factor(Aff.todense(), lower=True)
def deform_smooth_mesh(handle_vertex_positions):
    xc = handle_vertex_positions[labels>0, :]

    x = sp.linalg.spsolve(Aff, -Afc @ xc)
    v_smooth = handle_vertex_positions.copy()
    v_smooth[labels==0] = x

    return v_smooth

def deform_smooth_mesh_optional(handle_vertex_positions):
    xc = handle_vertex_positions[labels>0, :]

    x = cho_solve((c, low), -Afc @ xc, check_finite=False)
    v_smooth = handle_vertex_positions.copy()
    v_smooth[labels==0] = x

    return v_smooth

if option < 2:
    v_smooth_original = deform_smooth_mesh(v)
elif option == 2 or option == 3:
    v_smooth_original = deform_smooth_mesh_optional(v)
p = mp.plot(v_smooth_original, f, c=labels)<jupyter_output><empty_output><jupyter_text>Step 2 & 3:<jupyter_code>def encode_displacements(v_smooth_original):
    d = v - v_smooth_original
    normals_original = igl.per_vertex_normals(v_smooth_original, f)
    neighbors = igl.adjacency_list(f)
    j_longest = np.zeros(v.shape[0], dtype=np.int16)
    di = np.zeros_like(v)
    for i in range(v.shape[0]): 
        ni = normals_original[i]
        edges = v_smooth_original[neighbors[i]] - v_smooth_original[i]
        projected_edges = edges - edges @ ni[:, None] * ni
        neighbors_index = np.argmax(np.linalg.norm(projected_edges, axis=1))
        j_longest[i] = neighbors[i][neighbors_index]
        xi = projected_edges[neighbors_index]
        xi /= np.linalg.norm(xi)
        yi = np.cross(ni, xi)
        di[i] = np.array([d[i] @ xi, d[i] @ yi, d[i] @ ni])
    

    return di, j_longest

di, j_longest = encode_displacements(v_smooth_original)
def transfer_details(v_smooth_handle, di, j_longest):
    ni_prime = igl.per_vertex_normals(v_smooth_handle, f)
    v_detailed = v_smooth_handle.copy()
    edges = v_smooth_handle[j_longest] - v_smooth_handle
    xi_prime = np.empty_like(ni_prime)
    di_prime = np.empty_like(ni_prime)

    xi_prime = edges - np.sum(edges * ni_prime, axis=1).reshape(-1, 1) * ni_prime
    xi_prime /= np.linalg.norm(xi_prime).reshape(-1, 1)
    yi_prime = np.cross(ni_prime, xi_prime)
    for i in range(v.shape[0]):
        di_prime[i] = di[i] @ np.vstack((xi_prime[i], yi_prime[i], ni_prime[i]))
    
    v_detailed += di_prime
    
    return v_detailed
@jit(nopython=True)
def transfer_details_optional_jit(ni_prime, v_smooth_handle, di, j_longest):
    v_detailed = v_smooth_handle.copy()
    edges = v_smooth_handle[j_longest] - v_smooth_handle
    xi_prime = np.empty_like(ni_prime)
    di_prime = np.empty_like(ni_prime)
    
    xi_prime = edges - np.sum(edges * ni_prime, axis=1).reshape(-1, 1) * ni_prime
    for i in range(v.shape[0]):
        xi_prime[i] /= np.linalg.norm(xi_prime[i])

    yi_prime = np.cross(ni_prime, xi_prime)

    for i in range(v.shape[0]):
        di_prime[i] = di[i] @ np.vstack((xi_prime[i], yi_prime[i], ni_prime[i]))
    
    v_detailed += di_prime
    
    return v_detailed
def transfer_details_optional_enisum(ni_prime, v_smooth_handle, di, j_longest):
    v_detailed = v_smooth_handle.copy()
    edges = v_smooth_handle[j_longest] - v_smooth_handle
    xi_prime = np.empty_like(ni_prime)
    di_prime = np.empty_like(ni_prime)
    
    xi_prime = edges - np.einsum('ij,ij->i', edges, ni_prime)[:, None] * ni_prime
    xi_prime /= np.linalg.norm(xi_prime, axis=1)[:, None]

    yi_prime = np.cross(ni_prime, xi_prime)

    for i in range(v.shape[0]):
        di_prime[i] = np.einsum('i,ij', di[i], np.vstack((xi_prime[i], yi_prime[i], ni_prime[i])))

    v_detailed += di_prime
    
    return v_detailed
handle_vertex_positions = v.copy()
pos_f_saver = np.zeros((labels.max() + 1, 6))
def pos_f(s,x,y,z, α, β, γ):
    slices = (labels==s)
    r = Rotation.from_euler('xyz', [α, β, γ], degrees=True)
    v_slice = v[slices] + np.array([[x,y,z]])
    center = v_slice.mean(axis=0)
    handle_vertex_positions[slices] = r.apply(v_slice - center) + center
    pos_f_saver[s - 1] = [x,y,z,α,β,γ]
    t0 = time.time()
    v_deformed = pos_f.deformer(handle_vertex_positions)
    p.update_object(vertices = v_deformed)
    t1 = time.time()
    print('FPS', 1/(t1 - t0))

def position_deformer(target_pos):
    '''Fill in this function to change positions'''
    if option == 0:
        v_smooth_handle = deform_smooth_mesh(target_pos)
        return v_smooth_handle
    elif option == 1:
        v_smooth_handle = deform_smooth_mesh(target_pos)
        v_detailed = transfer_details(v_smooth_handle, di, j_longest)
        return v_detailed
    elif option == 2:
        v_smooth_handle = deform_smooth_mesh_optional(target_pos)
        # pp = mp.plot(v_smooth_handle, f, c=labels, shading={"wireframe": False})
        ni_prime = igl.per_vertex_normals(v_smooth_handle, f)
        v_detailed = transfer_details_optional_jit(ni_prime, v_smooth_handle, di, j_longest)
        return v_detailed
    elif option == 3:
        v_smooth_handle = deform_smooth_mesh_optional(target_pos)
        # pp = mp.plot(v_smooth_handle, f, c=labels, shading={"wireframe": False})
        ni_prime = igl.per_vertex_normals(v_smooth_handle, f)
        v_detailed = transfer_details_optional_enisum(ni_prime, v_smooth_handle, di, j_longest)
        return v_detailed
        
# (Optional) Register this function to perform interactive deformation
pos_f.deformer = position_deformer
## Widget UI

p = mp.plot(handle_vertex_positions, f, c=labels, shading={"wireframe": False})
iw.interact(pos_f,
            **widgets_wrapper())<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12887663680220537, 'fraction_numerical': 0.008270158511371467, 'mean_word_length': 3.833472106577852, 'pattern_counts': {'":': 3, '<': 10, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '2', 'dir': 'jupyter-structured-clean-dedup', 'id': '266796', 'license': 'MIT', 'n_tokens_mistral': 2379, 'n_tokens_neox': 2254, 'n_words': 393, 'path': 'Assignment_5/Assignment5.ipynb', 'repo_name': 'AmazingJinqi/gp', 'size': '5804'}