Esempio n. 1
0
def postSolve_setUpdateProgress(progress_min,
                                progress_value,
                                progress_max,
                                solres,  # SolveResult or None
                                prog_fn, status_fn):
    LOG.debug(
        'postSolve_setUpdateProgress: '
        'progress_min=%r '
        'progress_value=%r '
        'progress_max=%r '
        'solres=%r '
        'prog_fn=%r '
        'status_fn=%r',
        progress_min,
        progress_value,
        progress_max,
        solres,
        prog_fn, status_fn)
    stop_solving = False

    # Update progress
    ratio = float(progress_value) / float(progress_max)
    percent = float(progress_min) + (ratio * (100.0 - progress_min))
    collectionutils.run_progress_func(prog_fn, int(percent))

    # Check if the user wants to stop solving.
    if solres is None:
        cmd_cancel = False
    else:
        cmd_cancel = solres.get_user_interrupted()
    gui_cancel = api_state.get_user_interrupt()
    if cmd_cancel is True or gui_cancel is True:
        msg = 'Cancelled by User'
        api_state.set_user_interrupt(False)
        collectionutils.run_status_func(status_fn, 'WARNING: ' + msg)
        LOG.warning(msg)
        stop_solving = True
    if (solres is not None) and (solres.get_success() is False):
        msg = 'Solver failed!!!'
        collectionutils.run_status_func(status_fn, 'ERROR: ' + msg)
        LOG.error(msg)
    return stop_solving
Esempio n. 2
0
    def execute(
            self,
            verbose=False,
            # TODO: Refactor arguments into a 'Preferences' object
            # to hold the different preferences.
            refresh=False,
            force_update=False,
            do_isolate=False,
            # TODO: Allow a dict to be passed to the function
            # specifying the object type and the visibility status
            # during solving. This allows us to turn on/off any
            # object type during solving. If an argument is not
            # given or is None, the object type visibility will
            # not be changed.
            display_image_plane=False,
            prog_fn=None,
            status_fn=None,
            info_fn=None):
        """
        Compile the collection, then pass that data to the 'mmSolver' command.

        The mmSolver command will return a list of strings, which will then be
        passed to the SolveResult class so the user can query the raw data
        using an interface.

        :param verbose: Print extra solver information while a solve is
                        running.
        :type verbose: bool

        :param refresh: Should the solver refresh the viewport while
                        solving?
        :type refresh: bool

        :param force_update: Force updating the DG network, to help the
                             solver in case of a Maya evaluation DG bug.
        :type force_update: bool

        :param do_isolate: Isolate only solving objects while running solve.
        :type do_isolate: bool

        :param display_image_plane: Display Image Planes while solving?
        :type display_image_plane: bool

        :param prog_fn: The function used report progress messages to
                        the user.
        :type prog_fn: callable or None

        :param status_fn: The function used to report status messages
                          to the user.
        :type status_fn: callable or None

        :param info_fn: The function used to report information
                        messages to the user.
        :type info_fn: callable or None

        :return: List of SolveResults from the executed collection.
        :rtype: [SolverResult, ..]
        """
        start_time = time.time()

        # Ensure the plug-in is loaded, so we fail before trying to run.
        api_utils.load_plugin()

        # If 'refresh' is 'on' change all viewports to 'isolate
        # selected' on only the markers and bundles being solved. This
        # will speed up computations, especially per-frame solving as
        # it will not re-compute any invisible nodes (such as rigs or
        # image planes).
        panel_objs = {}
        panel_img_pl_vis = {}
        panels = viewport_utils.get_all_model_panels()
        if refresh is True:
            for panel in panels:
                if do_isolate is True:
                    state = maya.cmds.isolateSelect(panel,
                                                    query=True,
                                                    state=True)
                    nodes = None
                    if state is True:
                        nodes = viewport_utils.get_isolated_nodes(panel)
                    panel_objs[panel] = nodes
                panel_img_pl_vis[
                    panel] = viewport_utils.get_image_plane_visibility(panel)

        # Save current frame, to revert to later on.
        cur_frame = maya.cmds.currentTime(query=True)

        try:
            collectionutils.run_progress_func(prog_fn, 0)
            ts = solveresult.format_timestamp(time.time())
            collectionutils.run_status_func(status_fn, 'Solve start (%s)' % ts)
            api_state.set_solver_running(True)

            # Check for validity
            solres_list = []
            if self.is_valid() is False:
                LOG.warning('Collection not valid: %r', self.get_node())
                return solres_list
            kwargs_list = self._compile()
            collectionutils.run_progress_func(prog_fn, 1)

            # Isolate all nodes used in all of the kwargs to be run.
            # Note; This assumes the isolated objects are visible, but
            # they may actually be hidden.
            if refresh is True:
                s = time.time()
                if do_isolate is True:
                    isolate_nodes = set()
                    for kwargs in kwargs_list:
                        isolate_nodes |= collectionutils.generate_isolate_nodes(
                            kwargs)
                    if len(isolate_nodes) == 0:
                        raise excep.NotValid
                    isolate_node_list = list(isolate_nodes)
                    for panel in panels:
                        viewport_utils.set_isolated_nodes(
                            panel, isolate_node_list, True)

                for panel in panels:
                    viewport_utils.set_image_plane_visibility(
                        panel, display_image_plane)
                e = time.time()
                LOG.debug('Perform Pre-Isolate; time=%r', e - s)

            # Set the first current time to the frame before current.
            # This is to help trigger evaluations on the 'current
            # frame', if the current frame is the same as the first
            # frame.
            frame_list = []
            for kwargs in kwargs_list:
                frame_list += kwargs.get('frame', [])
            frame_list = list(set(frame_list))
            frame_list = list(sorted(frame_list))
            is_whole_solve_single_frame = len(frame_list) == 1
            if is_whole_solve_single_frame is False:
                s = time.time()
                maya.cmds.currentTime(
                    cur_frame - 1,
                    edit=True,
                    update=force_update,
                )
                e = time.time()
                LOG.debug('Update previous of current time; time=%r', e - s)

            # Run Solver...
            marker_nodes = []
            start = 0
            total = len(kwargs_list)
            for i, kwargs in enumerate(kwargs_list):
                frame = kwargs.get('frame')
                collectionutils.run_status_func(info_fn,
                                                'Evaluating frames %r' % frame)
                if frame is None or len(frame) == 0:
                    raise excep.NotValid

                # Write solver flags to a debug file.
                debug_file_path = kwargs.get('debugFile', None)
                if debug_file_path is not None:
                    options_file_path = debug_file_path.replace(
                        '.log', '.flags')
                    text = pprint.pformat(kwargs)
                    with open(options_file_path, 'w') as file_:
                        file_.write(text)

                # HACK: Overriding the verbosity, irrespective of what
                # the solver verbosity value is set to.
                if verbose is True:
                    kwargs['verbose'] = True

                # HACK for single frame solves.
                save_node_attrs = []
                is_single_frame = collectionutils.is_single_frame(kwargs)
                if is_single_frame is True:
                    save_node_attrs = collectionutils.disconnect_animcurves(
                        kwargs)

                # Run Solver Maya plug-in command
                solve_data = maya.cmds.mmSolver(**kwargs)

                # Revert special HACK for single frame solves
                if is_single_frame is True:
                    collectionutils.reconnect_animcurves(
                        kwargs, save_node_attrs)

                # Create SolveResult.
                solres = solveresult.SolveResult(solve_data)
                solres_list.append(solres)

                # Update progress
                ratio = float(i) / float(total)
                percent = float(start) + (ratio * (100.0 - start))
                collectionutils.run_progress_func(prog_fn, int(percent))

                # Check if the user wants to stop solving.
                cmd_cancel = solres.get_user_interrupted()
                gui_cancel = api_state.get_user_interrupt()
                if cmd_cancel is True or gui_cancel is True:
                    msg = 'Cancelled by User'
                    api_state.set_user_interrupt(False)
                    collectionutils.run_status_func(status_fn,
                                                    'WARNING: ' + msg)
                    LOG.warning(msg)
                    break
                if solres.get_success() is False:
                    msg = 'Solver failed!!!'
                    collectionutils.run_status_func(status_fn, 'ERROR: ' + msg)
                    LOG.error(msg)

                marker_nodes += [x[0] for x in kwargs.get('marker', [])]

                # Refresh the Viewport.
                if refresh is True:
                    # TODO: If we solve per-frame without "refresh"
                    # on, then we get wacky solvers
                    # per-frame. Interestingly, the 'force_update'
                    # does not seem to make a difference, just the
                    # 'maya.cmds.refresh' call.
                    #
                    # Test scene file:
                    # ./tests/data/scenes/mmSolverBasicSolveD_before.ma
                    s = time.time()
                    maya.cmds.currentTime(
                        frame[0],
                        edit=True,
                        update=force_update,
                    )
                    maya.cmds.refresh()
                    e = time.time()
                    LOG.debug('Refresh Viewport; time=%r', e - s)
        finally:
            if refresh is True:
                s = time.time()
                for panel, objs in panel_objs.items():
                    if objs is None:
                        # No original objects, disable 'isolate
                        # selected' after resetting the objects.
                        if do_isolate is True:
                            viewport_utils.set_isolated_nodes(panel, [], False)
                        img_pl_vis = panel_img_pl_vis.get(panel, True)
                        viewport_utils.set_image_plane_visibility(
                            panel, img_pl_vis)
                    else:
                        if do_isolate is True:
                            viewport_utils.set_isolated_nodes(
                                panel, list(objs), True)
                e = time.time()
                LOG.debug('Finally; reset isolate selected; time=%r', e - s)

            collectionutils.run_status_func(status_fn, 'Solve Ended')
            collectionutils.run_progress_func(prog_fn, 100)
            api_state.set_solver_running(False)

            maya.cmds.currentTime(cur_frame, edit=True, update=True)

        # Store output information of the solver.
        end_time = time.time()
        duration = end_time - start_time
        self._set_last_solve_timestamp(end_time)
        self._set_last_solve_duration(duration)
        self._set_last_solve_results(solres_list)
        return solres_list
def postSolve_setUpdateProgress(progress_min,
                                progress_value,
                                progress_max,
                                solres,
                                prog_fn, status_fn):
    """
    Update the Maya GUI with progress information, and detects users
    wanting to cancel the solve.

    :param progress_min:
        Minimum progress number possible.
        Usually the number is 0.
    :type progress_min: int

    :param progress_value:
        The actual progress value.
        The value is usually between 0 and 100 (inclusive).
    :type progress_value: int

    :param progress_max:
        THe maximum progress number possible.
        Usually the number is 100.
    :type progress_max: int

    :param solres:
        The SolveResult object for the last solved state.
    :type solres: SolveResult or None

    :param prog_fn: The function used report progress messages to
                    the user.
    :type prog_fn: callable or None

    :param status_fn: The function used to report status messages
                      to the user.
    :type status_fn: callable or None

    :returns:
        Should the solver stop executing or not? Has the user
        cancelled the solve?
    :rtype: bool
    """
    stop_solving = False

    # Update progress
    ratio = float(progress_value) / float(progress_max)
    percent = float(progress_min) + (ratio * (100.0 - progress_min))
    collectionutils.run_progress_func(prog_fn, int(percent))

    # Check if the user wants to stop solving.
    if solres is None:
        cmd_cancel = False
    else:
        cmd_cancel = solres.get_user_interrupted()
    gui_cancel = api_state.get_user_interrupt()
    if cmd_cancel is True or gui_cancel is True:
        msg = 'Cancelled by User'
        api_state.set_user_interrupt(False)
        collectionutils.run_status_func(status_fn, 'WARNING: ' + msg)
        LOG.warn(msg)
        stop_solving = True
    if (solres is not None) and (solres.get_success() is False):
        msg = 'Solver failed!!!'
        collectionutils.run_status_func(status_fn, 'ERROR: ' + msg)
        LOG.error(msg)
    return stop_solving