def get_last_solve_results(self): attr = const.COLLECTION_ATTR_LONG_NAME_SOLVER_RESULTS raw_data_list = self._get_attr_data(attr) solres_list = [] for raw_data in raw_data_list: solres = solveresult.SolveResult(raw_data) solres_list.append(solres) return solres_list
def _run_validate_action(vaction): """ Call a single validate action, and see what happens. :param vaction: Validation action object to be run. :type vaction: Action :return: A tuple of 3 parts; First, did the validation succeed (as boolean)? Second, the user message we present for the state. Third, metrics about the solve (number of parameters, number of errors, and number of frames to solve) :rtype: (bool, str, (int, int, int)) """ num_param = 0 num_err = 0 num_frames = 0 valid = True message = ('Validated parameters, errors and frames: ' 'param=%r errors=%r frames=%r') metrics = (num_param, num_err, num_frames) if not isinstance(vaction, api_action.Action): message = message % (num_param, num_err, num_frames) return valid, message, metrics vfunc, vargs, vkwargs = api_action.action_to_components(vaction) num_frames = len(vkwargs.get('frame', [])) if num_frames == 0: valid = False metrics = (num_param, num_err, num_frames) msg = ('Failed to validate number of frames: ' 'param=%r errors=%r frames=%r') message = msg % (num_param, num_err, num_frames) return valid, message, metrics vfunc_is_mmsolver = api_action.action_func_is_mmSolver(vaction) if vfunc_is_mmsolver is False: return valid, message, metrics solve_data = vfunc(*vargs, **vkwargs) solres = solveresult.SolveResult(solve_data) print_stats = solres.get_print_stats() num_param = print_stats.get('number_of_parameters', 0) num_err = print_stats.get('number_of_errors', 0) metrics = (num_param, num_err, num_frames) if num_param == 0 or num_err == 0 or num_param > num_err: valid = False msg = ('Failed to validate number of parameters and errors: ' 'param=%r errors=%r frames=%r') message = msg % (num_param, num_err, num_frames) return valid, message, metrics message = message % (num_param, num_err, num_frames) return valid, message, metrics
def _run_validate_action(vaction): num_param = 0 num_err = 0 num_frames = 0 valid = True message = ('Validated parameters, errors and frames: ' 'param=%r errors=%r frames=%r') metrics = (num_param, num_err, num_frames) if not isinstance(vaction, api_action.Action): message = message % (num_param, num_err, num_frames) return valid, message, metrics vfunc, vargs, vkwargs = api_action.action_to_components(vaction) num_frames = len(vkwargs.get('frame', [])) if num_frames == 0: valid = False metrics = (num_param, num_err, num_frames) msg = ('Failed to validate number of frames: ' 'param=%r errors=%r frames=%r') message = msg % (num_param, num_err, num_frames) return valid, message, metrics vfunc_is_mmsolver = api_action.action_func_is_mmSolver(vaction) if vfunc_is_mmsolver is False: return valid, message, metrics solve_data = vfunc(*vargs, **vkwargs) solres = solveresult.SolveResult(solve_data) print_stats = solres.get_print_stats() num_param = print_stats.get('number_of_parameters', 0) num_err = print_stats.get('number_of_errors', 0) metrics = (num_param, num_err, num_frames) if num_param == 0 or num_err == 0 or num_param > num_err: valid = False msg = ('Failed to validate number of parameters and errors: ' 'param=%r errors=%r frames=%r') message = msg % (num_param, num_err, num_frames) return valid, message, metrics message = message % (num_param, num_err, num_frames) return valid, message, metrics
def execute(self, verbose=False, refresh=False, prog_fn=None, status_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. :return: List of SolveResults from the executed collection. :rtype: [SolverResult, ..] """ # 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 = self.__get_all_model_panels() if refresh is True: for panel in panels: state = maya.cmds.isolateSelect( panel, query=True, state=True) nodes = None if state is True: nodes = self.__get_isolated_nodes(panel) panel_objs[panel] = nodes panel_img_pl_vis[panel] = self.__get_image_plane_visibility(panel) # Save current frame, to revert to later on. cur_frame = maya.cmds.currentTime(query=True) undo_state = maya.cmds.undoInfo(query=True, state=True) undo_id = 'mmSolver.api.collection.execute: ' + str(uuid.uuid4()) try: if undo_state is True: maya.cmds.undoInfo(openChunk=True, chunkName=undo_id) self.__set_progress(prog_fn, 0) self.__set_status(status_fn, 'Solver Initializing...') api_utils.set_solver_running(True) # 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. maya.cmds.currentTime( cur_frame - 1, edit=True, update=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() self.__set_progress(prog_fn, 1) # Isolate all nodes used in all of the kwargs to be run. if refresh is True: isolate_nodes = set() for kwargs in kwargs_list: isolate_nodes |= self.__generate_isolate_nodes(kwargs) if len(isolate_nodes) == 0: raise excep.NotValid isolate_node_list = list(isolate_nodes) for panel in panels: self.__set_image_plane_visibility(panel, False) self.__set_isolated_nodes(panel, isolate_node_list, True) # Run Solver... start = 0 total = len(kwargs_list) for i, kwargs in enumerate(kwargs_list): frame = kwargs.get('frame') self.__set_status(status_fn, 'Evaluating frames %r' % frame) if frame is None or len(frame) == 0: raise excep.NotValid 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 = self.__is_single_frame(kwargs) if is_single_frame is True: save_node_attrs = self.__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: self.__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)) self.__set_progress(prog_fn, int(percent)) if solres.get_success() is False: msg = 'Solver failed!!!' self.__set_status(status_fn, 'ERROR:' + msg) LOG.error(msg) # Refresh the Viewport. if refresh is True: maya.cmds.currentTime( frame[0], edit=True, update=True ) maya.cmds.refresh() except: solres_list = [] # TODO: If we have failed, should we attempt to clean up the mess # and undo the entire undo chunk? raise finally: if refresh is True: for panel, objs in panel_objs.items(): if objs is None: # No original objects, disable 'isolate # selected' after resetting the objects. self.__set_isolated_nodes(panel, [], False) img_pl_vis = panel_img_pl_vis.get(panel, True) self.__set_image_plane_visibility(panel, img_pl_vis) else: self.__set_isolated_nodes(panel, list(objs), True) self.__set_progress(prog_fn, 100) api_utils.set_solver_running(False) if undo_state is True: maya.cmds.undoInfo(closeChunk=True, chunkName=undo_id) maya.cmds.currentTime(cur_frame, edit=True, update=True) return solres_list
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 execute(self, verbose=False, refresh=False, prog_fn=None, status_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. :return: List of SolveResults :rtype: list of solveresult.SolverResult """ # Ensure the plug-in is loaded, so we fail before trying to run. api_utils.load_plugin() # Save current frame, to revert to later on. cur_frame = maya.cmds.currentTime(query=True) undo_state = maya.cmds.undoInfo(query=True, state=True) undo_id = 'mmSolver.api.collection.execute: ' + str(uuid.uuid4()) try: if undo_state is True: maya.cmds.undoInfo(openChunk=True, chunkName=undo_id) self.__set_progress(prog_fn, 0) self.__set_status(status_fn, 'Solver Initializing...') # 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() self.__set_progress(prog_fn, 1) # Run Solver... start = 0 total = len(kwargs_list) for i, kwargs in enumerate(kwargs_list): frame = kwargs.get('frame') self.__set_status(status_fn, 'Evaluating frames %r' % frame) if frame is None or len(frame) == 0: raise excep.NotValid # 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 = self.__is_single_frame(kwargs) if is_single_frame is True: save_node_attrs = self.__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: self.__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)) self.__set_progress(prog_fn, int(percent)) if solres.get_success() is False: msg = 'Solver failed!!!' self.__set_status(status_fn, 'ERROR:' + msg) LOG.error(msg) # Refresh the Viewport. if refresh is True: self.__set_status(status_fn, 'Refresh Viewport...') maya.cmds.currentTime( frame[0], edit=True, update=True ) maya.cmds.refresh() except: solres_list = [] # TODO: If we have failed, should we attempt to clean up the mess # and undo the entire undo chunk? raise finally: self.__set_progress(prog_fn, 100) if undo_state is True: maya.cmds.undoInfo(closeChunk=True, chunkName=undo_id) maya.cmds.currentTime(cur_frame, edit=True, update=True) return solres_list
def execute(col, options=None, validate_mode=None, log_level=None, 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 col: The Collection to execute. :type col: Collection :param options: The options for the execution. :type options: ExecuteOptions :param validate_mode: How should the solve validate? Must be one of the VALIDATE_MODE_VALUE_LIST values. :type validate_mode: str or None :param log_level: The log level for the execution. :type log_level: str :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, ..] """ if options is None: options = createExecuteOptions() if validate_mode is None: validate_mode = const.VALIDATE_MODE_NONE_VALUE assert validate_mode in const.VALIDATE_MODE_VALUE_LIST if log_level is None: log_level = const.LOG_LEVEL_DEFAULT assert isinstance(log_level, (str, unicode)) start_time = time.time() # Ensure the plug-in is loaded, so we fail before trying to run. api_utils.load_plugin() assert 'mmSolver' in dir(maya.cmds) vp2_state = viewport_utils.get_viewport2_active_state() panels = viewport_utils.get_all_model_panels() panel_objs, panel_node_type_vis = preSolve_queryViewportState( options, panels ) # Save current frame, to revert to later on. cur_frame = maya.cmds.currentTime(query=True) try: if options.disable_viewport_two is True: viewport_utils.set_viewport2_active_state(False) preSolve_updateProgress(prog_fn, status_fn) # Check for validity and compile actions. solres_list = [] withtest = validate_mode in [const.VALIDATE_MODE_PRE_VALIDATE_VALUE, const.VALIDATE_MODE_AT_RUNTIME_VALUE] col_node = col.get_node() sol_list = col.get_solver_list() mkr_list = col.get_marker_list() attr_list = col.get_attribute_list() try: s = time.time() action_list, vaction_list = api_compile.collection_compile( col_node, sol_list, mkr_list, attr_list, withtest=withtest, prog_fn=prog_fn, status_fn=status_fn ) e = time.time() LOG.debug('compile time (execute): %r', e - s) except excep.NotValid as e: LOG.warning(e) return solres_list collectionutils.run_progress_func(prog_fn, 1) if validate_mode == 'pre_validate': valid, msg, metrics_list = _run_validate_action_list(vaction_list) if valid is not True: LOG.warning(msg) return solres_list # Prepare frame solve preSolve_setIsolatedNodes(action_list, options, panels) preSolve_triggerEvaluation(action_list, cur_frame, options) # Run Solver Actions... start = 0 total = len(action_list) for i, (action, vaction) in enumerate(zip(action_list, vaction_list)): if isinstance(vaction, api_action.Action) and validate_mode == 'at_runtime': valid, message, metrics = _run_validate_action(vaction) if valid is not True: LOG.warn(message) return func, args, kwargs = api_action.action_to_components(action) func_is_mmsolver = api_action.action_func_is_mmSolver(action) save_node_attrs = None is_single_frame = None if func_is_mmsolver is True: 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) # Overriding the verbosity, irrespective of what # the solver verbosity value is set to. if log_level is not None and log_level.lower() == 'verbose': 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 = func(*args, **kwargs) # Revert special HACK for single frame solves if func_is_mmsolver is True: if is_single_frame is True: collectionutils.reconnect_animcurves(kwargs, save_node_attrs) # Create SolveResult. solres = None if solve_data is not None and func_is_mmsolver is True: solres = solveresult.SolveResult(solve_data) solres_list.append(solres) # Update Progress interrupt = postSolve_setUpdateProgress( start, i, total, solres, prog_fn, status_fn ) if interrupt is True: break # Refresh the Viewport. if func_is_mmsolver is True: frame = kwargs.get('frame') postSolve_refreshViewport(options, frame) finally: postSolve_setViewportState( options, panel_objs, panel_node_type_vis ) collectionutils.run_status_func(status_fn, 'Solve Ended') collectionutils.run_progress_func(prog_fn, 100) api_state.set_solver_running(False) if options.disable_viewport_two is True: viewport_utils.set_viewport2_active_state(vp2_state) maya.cmds.currentTime( cur_frame, edit=True, update=options.force_update ) # Store output information of the solver. end_time = time.time() duration = end_time - start_time col._set_last_solve_timestamp(end_time) col._set_last_solve_duration(duration) col._set_last_solve_results(solres_list) return solres_list
def execute(col, options=None, validate_mode=None, log_level=None, 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 col: The Collection to execute. :type col: Collection :param options: The options for the execution. :type options: ExecuteOptions :param validate_mode: How should the solve validate? Must be one of the VALIDATE_MODE_VALUE_LIST values. :type validate_mode: str or None :param log_level: The log level for the execution. :type log_level: str :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, ..] """ if options is None: options = createExecuteOptions() if validate_mode is None: validate_mode = const.VALIDATE_MODE_PRE_VALIDATE_VALUE assert validate_mode in const.VALIDATE_MODE_VALUE_LIST if log_level is None: log_level = const.LOG_LEVEL_DEFAULT assert isinstance(log_level, pycompat.TEXT_TYPE) validate_runtime = validate_mode == const.VALIDATE_MODE_AT_RUNTIME_VALUE validate_before = validate_mode == const.VALIDATE_MODE_PRE_VALIDATE_VALUE start_time = time.time() # Ensure the plug-in is loaded, so we (do not) fail before trying # to run. api_utils.load_plugin() assert 'mmSolver' in dir(maya.cmds) vp2_state = viewport_utils.get_viewport2_active_state() current_eval_manager_mode = maya.cmds.evaluationManager(query=True, mode=True) panels = viewport_utils.get_all_model_panels() panel_objs, panel_node_type_vis = preSolve_queryViewportState( options, panels) # Save scene state, to revert to later on. cur_frame = maya.cmds.currentTime(query=True) prev_auto_key_state = maya.cmds.autoKeyframe(query=True, state=True) prev_cycle_check = maya.cmds.cycleCheck(query=True, evaluation=True) # State information needed to revert reconnect animation curves in # 'finally' block. kwargs = {} save_node_attrs = [] func_is_mmsolver = False is_single_frame = False try: if options.disable_viewport_two is True: viewport_utils.set_viewport2_active_state(False) maya.cmds.autoKeyframe(edit=True, state=False) maya.cmds.evaluationManager(mode='off') maya.cmds.cycleCheck(evaluation=False) preSolve_updateProgress(prog_fn, status_fn) # Check for validity and compile actions. solres_list = [] withtest = validate_mode in [ const.VALIDATE_MODE_PRE_VALIDATE_VALUE, const.VALIDATE_MODE_AT_RUNTIME_VALUE ] sol_list = col.get_solver_list() mkr_list = col.get_marker_list() attr_list = col.get_attribute_list() try: action_list, vaction_list = api_compile.collection_compile( col, sol_list, mkr_list, attr_list, withtest=withtest, prog_fn=prog_fn, status_fn=status_fn) except excep.NotValid as e: LOG.warn(e) return solres_list collectionutils.run_progress_func(prog_fn, 1) vaction_state_list = [] if validate_before is True: vaction_state_list = _run_validate_action_list(vaction_list) assert len(vaction_list) == len(vaction_state_list) # Prepare frame solve preSolve_setIsolatedNodes(action_list, options, panels) preSolve_triggerEvaluation(action_list, cur_frame, options) # Ensure prediction attributes are created and initialised. collectionutils.set_initial_prediction_attributes( col, attr_list, cur_frame) # Run Solver Actions... message_hashes = set() start = 0 total = len(action_list) number_of_solves = 0 for i, (action, vaction) in enumerate(zip(action_list, vaction_list)): state = None if len(vaction_state_list) > 0: # We have pre-computed the state list. state = vaction_state_list[i] if isinstance(vaction, api_action.Action) and validate_runtime: # We will calculate the state just-in-time. state = _run_validate_action(vaction) if state is not None: if state.status != const.ACTION_STATUS_SUCCESS: assert isinstance(state, ActionState) h = hash(state.message) if h not in message_hashes: LOG.warn(state.message) message_hashes.add(h) # Skip this action, since the test failed. continue func, args, kwargs = api_action.action_to_components(action) func_is_mmsolver = api_action.action_func_is_mmSolver(action) if func_is_mmsolver is True: 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) # Overriding the verbosity, irrespective of what the # solver verbosity value is set to. kwargs['verbose'] = False if log_level is not None and log_level.lower() == 'verbose': kwargs['verbose'] = True # HACK for single frame solves. is_single_frame = collectionutils.is_single_frame(kwargs) if is_single_frame is True: save_node_attrs = collectionutils.disconnect_animcurves( kwargs) else: # Reset the data structure so in the 'finally' # block we can detect animcurves are not needing # to be reset. save_node_attrs = [] # Run Solver Maya plug-in command solve_data = func(*args, **kwargs) # Revert special HACK for single frame solves if func_is_mmsolver is True: if is_single_frame is True: collectionutils.reconnect_animcurves( kwargs, save_node_attrs) # Reset the data structure so in the 'finally' # block we can detect animcurves are not needing # to be reset. save_node_attrs = [] # Create SolveResult. solres = None if solve_data is not None and func_is_mmsolver is True: solres = solveresult.SolveResult(solve_data) solres_list.append(solres) if func_is_mmsolver is True and solres.get_success() is True: frame = kwargs.get('frame') if frame is None or len(frame) == 0: raise excep.NotValid single_frame = frame[0] if number_of_solves == 0: collectionutils.set_initial_prediction_attributes( col, attr_list, single_frame) # Count number of solves, so we don't need to set the # initial prediction attributes again. number_of_solves += 1 # Calculate the mean, variance values, and predict the # next attribute value. collectionutils.compute_attribute_value_prediction( col, attr_list, single_frame, ) # Update Progress interrupt = postSolve_setUpdateProgress(start, i, total, solres, prog_fn, status_fn) if interrupt is True: break # Refresh the Viewport. if func_is_mmsolver is True: frame = kwargs.get('frame') postSolve_refreshViewport(options, frame) finally: # If something has gone wrong, or the user cancels the solver # without finishing, then we make sure to reconnect animcurves # that were disconnected for single frame solves. if func_is_mmsolver is True and is_single_frame is True: if len(save_node_attrs): collectionutils.reconnect_animcurves(kwargs, save_node_attrs) postSolve_setViewportState(options, panel_objs, panel_node_type_vis) collectionutils.run_status_func(status_fn, 'Solve Ended') collectionutils.run_progress_func(prog_fn, 100) maya.cmds.evaluationManager(mode=current_eval_manager_mode[0]) maya.cmds.cycleCheck(evaluation=prev_cycle_check) maya.cmds.autoKeyframe(edit=True, state=prev_auto_key_state) api_state.set_solver_running(False) if options.disable_viewport_two is True: viewport_utils.set_viewport2_active_state(vp2_state) maya.cmds.currentTime(cur_frame, edit=True, update=options.force_update) # Store output information of the solver. end_time = time.time() duration = end_time - start_time col._set_last_solve_timestamp(end_time) col._set_last_solve_duration(duration) col._set_last_solve_results(solres_list) return solres_list
def _run_validate_action(vaction): """ Call a single validate action, and see what happens. :param vaction: Validation action object to be run. :type vaction: Action :return: A tuple of 3 parts; First, did the validation succeed (as boolean)? Second, the user message we present for the state. Third, metrics about the solve (number of parameters, number of errors, and number of frames to solve) :rtype: ActionState """ if not isinstance(vaction, api_action.Action): state = _create_action_state(status=const.ACTION_STATUS_SUCCESS, message='Action cannot be run.') return state vfunc, vargs, vkwargs = api_action.action_to_components(vaction) vfunc_is_mmsolver = api_action.action_func_is_mmSolver(vaction) num_param = 0 num_err = 0 frames = list(sorted(vkwargs.get('frame', []))) num_frames = len(frames) if num_frames == 0 and vfunc_is_mmsolver is True: msg = ('Failed to validate number of frames: ' 'param=%r errors=%r frames=%r') message = msg % (num_param, num_err, num_frames) state = _create_action_state(status=const.ACTION_STATUS_FAILED, message=message, error_number=num_err, parameter_number=num_param, frames_number=num_frames, frames=frames) return state # Run validate function solve_data = vfunc(*vargs, **vkwargs) if vfunc_is_mmsolver is False: msg = ('Validated parameters, errors and frames: ' 'param=%r errors=%r frames=%r') message = msg % (num_param, num_err, num_frames) state = _create_action_state(status=const.ACTION_STATUS_SUCCESS, message=message, error_number=num_err, parameter_number=num_param, frames_number=num_frames, frames=frames) return state solres = solveresult.SolveResult(solve_data) print_stats = solres.get_print_stats() num_param = print_stats.get('number_of_parameters', 0) num_err = print_stats.get('number_of_errors', 0) if num_param == 0 or num_err == 0 or num_param > num_err: msg = 'Invalid parameters and errors, skipping solve: %r' message = msg % list(sorted(frames)) state = _create_action_state(status=const.ACTION_STATUS_FAILED, message=message, error_number=num_err, parameter_number=num_param, frames_number=num_frames, frames=frames) return state msg = ('Validated parameters, errors and frames: ' 'param=%r errors=%r frames=%r') message = msg % (num_param, num_err, num_frames) state = _create_action_state(status=const.ACTION_STATUS_SUCCESS, message=message, error_number=num_err, parameter_number=num_param, frames_number=num_frames, frames=frames) return state