예제 #1
0
def preferred_score(given_well, alignment):
    """combine distance from the given node to the gravity well, and the
    node's current alignment status for a preference score
    """
    node_center = alignment.anode.center
    distance = pos._2d_distance(node_center, given_well)
    x, y = given_well
    num_aligned_nodes = len([
        n for n in alignment.ancillaries
        if x == pos.center(n)[0] or y == pos.center(n)[1]
    ])
    final_score = distance / num_aligned_nodes
    return final_score
예제 #2
0
def find_common_axis(nodes=None):
    """return the axis along which the given nodes are already aligned,
    if any.
    """
    centers = [pos.center(n) for n in nodes]
    x_counter = Counter([c[0] for c in centers])
    y_counter = Counter([c[1] for c in centers])
    common_x = x_counter.most_common(2)
    common_y = y_counter.most_common(2)
    if common_x[0][1] > common_y[0][1]:
        if common_x[0][1] == len(nodes):
            return ('y', 'aligned')
        elif common_x[0][1] != common_x[1][1]:
            return ('x', common_x[0][0])
        else:
            return None
    elif common_y[0][1] > common_x[0][1]:
        if common_y[0][1] == len(nodes):
            return ('x', 'aligned')
        elif common_y[0][1] != common_y[1][1]:
            return ('y', common_y[0][0])
        else:
            return None
    else:
        return None
예제 #3
0
def align_selected(nodes=None):
    """align nodes based on current selection"""
    if len(nodes) == 1:
        node = nodes[0]
        cur_pos = (node.xpos(), node.ypos())
        with utils.Undoable_Action():
            preferred(node=node)
            if cur_pos == (node.xpos(), node.ypos()):
                cycle_wells(node=node)
    else:
        common_axis = find_common_axis(nodes)
        if common_axis:
            axis, position = common_axis
            if position == 'aligned':
                move.space_out_nodes(axis=axis, nodes=nodes)
            else:
                with utils.Undoable_Action():
                    for n in nodes:
                        move.center_to(n, **{axis: position})
        else:
            root_node = max(nodes, key=pre_aligned_score)
            root_pos = pos.center(root_node)
            bbox = pos.group_bounding_box(nodes)
            if bbox[2] - bbox[0] > bbox[3] - bbox[1]:
                mover = 'y'
                axis = 1
            else:
                mover = 'x'
                axis = 0
            with utils.Undoable_Action():
                for n in nodes:
                    move.center_to(n, **{mover: root_pos[axis]})
예제 #4
0
 def __init__(self, node):
     super(AlignableNode, self).__init__()
     self.node = node
     self.name = node.name()
     self.corner = pos.xy(node)
     self.center = pos.center(node)
     self.node_class = node.Class()
     self.join = False
예제 #5
0
def gravity_wells(nodes):
    """return all possible alignments for a set of nodes"""
    node_centers = [pos.center(n) for n in nodes]
    wells = [(x[0], y[1]) for x in node_centers for y in node_centers
             if (x[0], y[1]) not in node_centers]
    # If there are no wells, then the ancillaries are all in a line.
    unique_wells = list(set(wells))
    return sorted(unique_wells, key=lambda x: wells.index(x))
예제 #6
0
def space_out_nodes(nodes=None, axis='x'):
    """space out nodes along the given axis"""
    axes = ('x', 'y')
    axis_index = axes.index(axis)
    constrained_axis = 1 - axis_index
    min_node = pos.xmost_node(nodes=nodes, axis=axis, min_max=min)
    max_node = pos.xmost_node(nodes=nodes, axis=axis, min_max=max)
    min_pos = pos.center(min_node)
    max_pos = pos.center(max_node)
    min_on_axis = min_pos[axis_index]
    max_on_axis = max_pos[axis_index]
    constrained = min_pos[constrained_axis]
    interval = int(max_on_axis - min_on_axis) / (len(nodes) - 1)
    nodes.sort(key=lambda x: x['{}pos'.format(axis)].value())
    # nodes.pop()
    for i, node in enumerate(nodes):
        npos = [0, 0]
        npos[constrained_axis] = constrained
        npos[axis_index] = min_on_axis + (i * interval)
        center_to(node=node, x=npos[0], y=npos[1])
예제 #7
0
def to_relative(node_one, node_two, x=0, y=0):
    """base function for moving nodes relative to each other. node_one is
    always relative to node_two
    """
    cen_x, cen_y = pos.center(node_two)
    center_to(node_one, cen_x, cen_y)
    axis = 'x' if x else 'y'
    node_offset = _node_offsets(node_one, node_two, axis)
    if x < 0 or y < 0:
        node_offset = -node_offset
    if x:
        x += node_offset
    elif y:
        y += node_offset
    nudge(node_one, x, y)
예제 #8
0
def cycle_wells(node=None):
    """align the node to the next available gravity well"""
    alignment = Node_Alignment(node)
    node_center = alignment.anode.center
    wells = alignment.wells
    all_centers = [pos.center(n) for n in alignment.ancillaries]
    wells.sort(key=lambda x: wells_score(x, all_centers))
    if wells:
        if node_center in wells:
            try:
                final_well = wells[wells.index(node_center) + 1]
            except IndexError:
                final_well = wells[0]
        else:
            final_well = wells[0]
        move.center_to(node, *final_well)
    else:
        pass
예제 #9
0
 def _sort_wells(self):
     all_centers = [pos.center(a) for a in self.ancillaries]
     self.wells.sort(key=lambda x: (wells_score(x, all_centers)))
예제 #10
0
def expand_contract(direction, expand_or_contract, amt=.1, nodes=None):
    """expands a set of nodes in a given direction.
    direction can be left, right, up, down, topleft, topright, botleft,
    botright, xaxis, yaxis, or center."""

    # TODO: needs a good pep-8-ing and probably a good refactoring
    if direction in ('left', 'right', 'up', 'down'):
        graphNodes = [n for n in nodes if n.Class() != 'BackdropNode']
        backdropNodes = [n for n in nodes if n.Class() == 'BackdropNode']

        # get the bounding box
        xmin, ymin, xmax, ymax = pos.group_bounding_box(nodes)

        # ------------------- Direction of Movement ----------------------- #
        if expand_or_contract == 'expand':
            amt = 1 + amt
        else:
            amt = 1 - amt
        if direction == 'down':
            total = ymax - ymin
            target = (total * amt) - total
            offsetter = 1
            anchor = ymin

        if direction == 'up':
            total = ymax - ymin
            target = -1 * ((total * amt) - total)
            offsetter = 1
            anchor = ymax

        if direction == 'left':
            total = xmax - xmin
            target = -1 * ((total * amt) - total)
            offsetter = 0
            anchor = xmax

        if direction == 'right':
            total = xmax - xmin
            target = (total * amt) - total
            offsetter = 0
            anchor = xmin
        # If the destination is the same as the origin, skip evaluation
        if total == 0:
            return

        # ------------------- Move Nodes ---------------------------------- #
        for n in graphNodes:
            offAxis = pos.center(n)[offsetter]
            offset = abs(offAxis - anchor)
            offsetRatio = float(offset) / float(total)
            offsetBy = target * offsetRatio
            n[('xpos', 'ypos')[offsetter]].setValue(
                int(n[('xpos', 'ypos')[offsetter]].getValue() + offsetBy))

        # ------------------- Handle Backdrops ---------------------------- #
        for bn in backdropNodes:
            if direction == 'down' or direction == 'up':
                offsetTop = abs(bn['ypos'].getValue() - anchor)
                otRatio = offsetTop / total
                offsetBottom = abs((bn['ypos'].getValue() +
                                    bn['bdheight'].getValue()) - anchor)
                obRatio = offsetBottom / total

                offsetTopBy = target * otRatio
                offsetBottomBy = (target * obRatio) - offsetTopBy

                bn['ypos'].setValue(int(bn['ypos'].getValue() + offsetTopBy))
                bn['bdheight'].setValue(
                    int(bn['bdheight'].getValue() + offsetBottomBy))

            if direction == 'left' or direction == 'right':
                offsetLeft = abs(bn['xpos'].getValue() - anchor)
                olRatio = offsetLeft / total
                offsetRight = abs((bn['xpos'].getValue() +
                                   bn['bdwidth'].getValue()) - anchor)
                orRatio = offsetRight / total
                offsetLeftBy = target * olRatio
                offsetRightBy = (target * orRatio) - offsetLeftBy
                bn['xpos'].setValue(int(bn['xpos'].getValue() + offsetLeftBy))
                bn['bdwidth'].setValue(
                    int(bn['bdwidth'].getValue() + offsetRightBy))

    # ------------------- Macros ------------------------------------------ #
    elif direction == 'yaxis':
        expand_contract('up', expand_or_contract, (float(amt) / 2.0), nodes)
        expand_contract('down', expand_or_contract, (float(amt) / 2.0), nodes)
    elif direction == 'xaxis':
        expand_contract('left', expand_or_contract, (float(amt) / 2.0), nodes)
        expand_contract('right', expand_or_contract, (float(amt) / 2.0), nodes)
    elif direction == 'botright':
        expand_contract('left', expand_or_contract, amt, nodes)
        expand_contract('up', expand_or_contract, amt, nodes)
    elif direction == 'botleft':
        expand_contract('right', expand_or_contract, amt, nodes)
        expand_contract('up', expand_or_contract, amt, nodes)
    elif direction == 'topleft':
        expand_contract('right', expand_or_contract, amt, nodes)
        expand_contract('down', expand_or_contract, amt, nodes)
    elif direction == 'topleft':
        expand_contract('right', expand_or_contract, amt, nodes)
        expand_contract('down', expand_or_contract, amt, nodes)
    elif direction == 'topright':
        expand_contract('left', expand_or_contract, amt, nodes)
        expand_contract('down', expand_or_contract, amt, nodes)
    elif direction == 'center':
        expand_contract('left', expand_or_contract, (float(amt) / 2.0), nodes)
        expand_contract('right', expand_or_contract, (float(amt) / 2.0), nodes)
        expand_contract('up', expand_or_contract, (float(amt) / 2.0), nodes)
        expand_contract('down', expand_or_contract, (float(amt) / 2.0), nodes)
    else:
        pass
예제 #11
0
def center_to(node=None, x=None, y=None):
    """move the center of the node to the specified coordinates"""
    cen_x, cen_y = pos.center(node)
    move_by_x = x - cen_x if x else 0
    move_by_y = y - cen_y if y else 0
    nudge(node, move_by_x, move_by_y)