def gather_positions(tree):
    """Makes a list of positions and position commands from the tree"""
    pos = {'data-x': 'r0',
           'data-y': 'r0',
           'data-z': 'r0',
           'data-rotate-x': 'r0',
           'data-rotate-y': 'r0',
           'data-rotate-z': 'r0',
           'data-scale': 'r0',
           'is_path': False
           }

    steps = 0
    default_movement = True

    for step in tree.findall('step'):
        steps += 1

        for key in POSITION_ATTRIBS:
            value = step.get(key)

            if value is not None:
                # We have a new value
                default_movement = False  # No longer use the default movement
                pos[key] = value
            elif pos[key] and not pos[key].startswith('r'):
                # The old value was absolute and no new value, so stop
                pos[key] = 'r0'
            # We had no new value, and the old value was a relative
            # movement, so we just keep moving.

        if steps == 1 and pos['data-scale'] == 'r0':
            # No scale given for first slide, it needs to start at 1
            pos['data-scale'] = '1'

        if default_movement and steps != 1:
            # No positioning has been given, use default:
            pos['data-x'] = 'r%s' % DEFAULT_MOVEMENT

        if 'data-rotate' in step.attrib:
            # data-rotate is an alias for data-rotate-z
            pos['data-rotate-z'] = step.get('data-rotate')
            del step.attrib['data-rotate']

        if 'hovercraft-path' in step.attrib:
            # Path given x and y will be calculated from the path
            default_movement = False  # No longer use the default movement
            pos['is_path'] = True
            # Add the path spec
            pos['path'] = step.attrib['hovercraft-path']
            yield pos.copy()
            # And get rid of it for the next step
            del pos['path']
        else:
            if 'data-x' in step.attrib or 'data-y' in step.attrib:
                # No longer using a path
                pos['is_path'] = False
            yield pos.copy()
Makes a list of positions and position commands from the tree