def preSolve_setIsolatedNodes(actions_list, options, panels): """ Prepare frame solve 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 options.refresh is not True: return if options.do_isolate is True: isolate_nodes = set() for action in actions_list: kwargs = action.kwargs 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) display_node_types = options.display_node_types if display_node_types is not None: assert isinstance(display_node_types, dict) for panel in panels: for node_type, value in display_node_types.items(): if value is None: continue assert isinstance(value, bool) viewport_utils.set_node_type_visibility(panel, node_type, value) return
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