Exemplo n.º 1
0
def dual_contour_2d_find_best_vertex(f, f_normal, x, y):
    if not ADAPTIVE:
        return V2(x + 0.5, y + 0.5)

    # Evaluate
    x0y0 = f(x + 0.0, y + 0.0)
    x0y1 = f(x + 0.0, y + 1.0)
    x1y0 = f(x + 1.0, y + 0.0)
    x1y1 = f(x + 1.0, y + 1.0)

    # For each edge, identify where there is a sign change
    changes = []
    if (x0y0 > 0) != (x0y1 > 0):
        changes.append([x + 0, y + adapt(x0y0, x0y1)])
    if (x1y0 > 0) != (x1y1 > 0):
        changes.append([x + 1, y + adapt(x1y0, x1y1)])
    if (x0y0 > 0) != (x1y0 > 0):
        changes.append([x + adapt(x0y0, x1y0), y + 0])
    if (x0y1 > 0) != (x1y1 > 0):
        changes.append([x + adapt(x0y1, x1y1), y + 1])

    if len(changes) <= 1:
        return None

    # For each sign change location v[i], we find the normal n[i].

    normals = []
    for v in changes:
        n = f_normal(v[0], v[1])
        normals.append([n.x, n.y])

    v = solve_qef_2d(x, y, changes, normals)

    return v
Exemplo n.º 2
0
def dual_contour_3d_find_best_vertex(f, f_normal, x, y, z):
    if not ADAPTIVE:
        return V3(x + 0.5, y + 0.5, z + 0.5)

    # Evaluate f at each corner
    v = np.empty((2, 2, 2))
    for dx in (0, 1):
        for dy in (0, 1):
            for dz in (0, 1):
                v[dx, dy, dz] = f(x + dx, y + dy, z + dz)

    # For each edge, identify where there is a sign change.
    # There are 4 edges along each of the three axes
    changes = []
    for dx in (0, 1):
        for dy in (0, 1):
            if (v[dx, dy, 0] > 0) != (v[dx, dy, 1] > 0):
                changes.append(
                    (x + dx, y + dy, z + adapt(v[dx, dy, 0], v[dx, dy, 1])))

    for dx in (0, 1):
        for dz in (0, 1):
            if (v[dx, 0, dz] > 0) != (v[dx, 1, dz] > 0):
                changes.append(
                    (x + dx, y + adapt(v[dx, 0, dz], v[dx, 1, dz]), z + dz))

    for dy in (0, 1):
        for dz in (0, 1):
            if (v[0, dy, dz] > 0) != (v[1, dy, dz] > 0):
                changes.append(
                    (x + adapt(v[0, dy, dz], v[1, dy, dz]), y + dy, z + dz))

    if len(changes) <= 1:
        return None

    # For each sign change location v[i], we find the normal n[i].
    # The error term we are trying to minimize is sum( dot(x-v[i], n[i]) ^ 2)

    # In other words, minimize || A * x - b || ^2 where A and b are a matrix and vector
    # derived from v and n

    normals = []
    for v in changes:
        n = f_normal(v[0], v[1], v[2])
        normals.append([n.x, n.y, n.z])

    return solve_qef_3d(x, y, z, changes, normals)
Exemplo n.º 3
0
 def edge_to_boundary_vertex(edge):
     """Returns the vertex in the middle of the specified edge"""
     # Find the two vertices specified by this edge, and interpolate between
     # them according to adapt, as in the 2d case
     v0, v1 = EDGES[edge]
     f0 = f_eval[v0]
     f1 = f_eval[v1]
     t0 = 1 - adapt(f0, f1)
     t1 = 1 - t0
     vert_pos0 = VERTICES[v0]
     vert_pos1 = VERTICES[v1]
     return V3(x + vert_pos0[0] * t0 + vert_pos1[0] * t1,
               y + vert_pos0[1] * t0 + vert_pos1[1] * t1,
               z + vert_pos0[2] * t0 + vert_pos1[2] * t1)
Exemplo n.º 4
0
    case = ((1 if x0y0 > 0 else 0) + (2 if x0y1 > 0 else 0) +
            (4 if x1y0 > 0 else 0) + (8 if x1y1 > 0 else 0))

    # Several of the cases are inverses of each other where solid is non solid and visa versa
    # They have the same boundary, which cuts down the cases a bit.
    # But we swap the direction of the boundary, so that edges are always winding clockwise around the solid.
    # Getting those swaps correct isn't needed for our simple visualizations, but is important in other uses cases
    # particularly in 3d.

    if case is 0 or case is 15:
        # All outside / inside
        return []
    if case is 1 or case is 14:
        # Single corner
        return [
            Edge(V2(x + 0 + adapt(x0y0, x1y0), y),
                 V2(x + 0, y + adapt(x0y0, x0y1))).swap(case is 14)
        ]
    if case is 2 or case is 13:
        # Single corner
        return [
            Edge(V2(x + 0, y + adapt(x0y0, x0y1)),
                 V2(x + adapt(x0y1, x1y1), y + 1)).swap(case is 11)
        ]
    if case is 4 or case is 11:
        # Single corner
        return [
            Edge(V2(x + 1, y + adapt(x1y0, x1y1)),
                 V2(x + adapt(x0y0, x1y0), y + 0)).swap(case is 13)
        ]
    if case is 8 or case is 7: