def are_edges_coplanar(c, e1, e2, e3, threshold=0.1):
    cross = lambda x,y: geom.Vertex(funchelps.cross(x,y))
    gc = blender.convert_vert(c)
    ge1 = blender.convert_vert(e1)
    ge2 = blender.convert_vert(e2)
    ge3 = blender.convert_vert(e3)
    return abs(funchelps.dot(cross(ge1 - gc, ge2 - gc), ge3 - gc)) < threshold
def create_function_from_patch(mesh, patch): #TODO This should be customized
    curves = []
    for edge in patch:
        verts = (tuple((blender.convert_vert(mesh.verts[i]) for i in edge)))
        curves.append(geom.generate_spline(verts, mmath.interp_bezier_curve_2))
    return geom.PolygonsNetQuad(curves)
    return curves
def size_estimate(bm):
    '''Returns an estimate of the mesh size. '''
    verts_list = [blender.convert_vert(v) for v in bm.verts]
    
    def axis_length(index, vs):
        axis = [v[index] for v in vs]
        return max(axis) - min(axis)
    
    return max(axis_length(0, verts_list), axis_length(1, verts_list), axis_length(2, verts_list))
def compute_angle_blender(bA, bB, bC):
    '''Same as compute_angle but with blender edges.'''
    points = tuple([blender.convert_vert(v) for v in [bA, bB, bC]])
    return compute_angle(*points)
def compute_patch_error(patch, bm, patch_verts_attribution):
    patch_func = create_function_from_patch(bm, patch)
    #patch_func_points = list(geom.sample_patch_samples(patch_func, math.sqrt(10 * len(patch_verts_attribution)) // 1))
    patch_func_points = list(geom.sample_patch_samples_uv(patch_func, len(patch[0]), len(patch[1])))
    patch_verts = [blender.convert_vert(bm.verts[vi]) for vi in patch_verts_attribution]
    return errors.verts_max_error(patch_func_points, patch_verts)