From e53dc0a0debcfc1ad8f98ba65c8af17981abaa0c Mon Sep 17 00:00:00 2001 From: BrandonPacewic <92102436+BrandonPacewic@users.noreply.github.com> Date: Wed, 21 Aug 2024 10:31:42 -0700 Subject: [PATCH 1/4] Remove unused code --- exporter/SynthesisFusionAddin/src/Types.py | 3 + .../SynthesisFusionAddin/src/UI/Camera.py | 2 +- .../src/UI/ConfigCommand.py | 258 ++---------------- .../src/UI/Configuration/SerialCommand.py | 104 ------- .../SynthesisFusionAddin/src/UI/Handlers.py | 107 -------- 5 files changed, 21 insertions(+), 453 deletions(-) delete mode 100644 exporter/SynthesisFusionAddin/src/UI/Configuration/SerialCommand.py diff --git a/exporter/SynthesisFusionAddin/src/Types.py b/exporter/SynthesisFusionAddin/src/Types.py index 5e2d7c967..82169e0f5 100644 --- a/exporter/SynthesisFusionAddin/src/Types.py +++ b/exporter/SynthesisFusionAddin/src/Types.py @@ -5,6 +5,8 @@ from enum import Enum, EnumType from typing import Any, TypeAlias, get_args, get_origin +import adsk.fusion + # Not 100% sure what this is for - Brandon JointParentType = Enum("JointParentType", ["ROOT", "END"]) @@ -85,6 +87,7 @@ def toKg(pounds: LBS) -> KG: PRIMITIVES = (bool, str, int, float, type(None)) +SELECTABLE_JOINT_TYPES = (adsk.fusion.JointTypes.RevoluteJointType, adsk.fusion.JointTypes.SliderJointType) def encodeNestedObjects(obj: Any) -> Any: diff --git a/exporter/SynthesisFusionAddin/src/UI/Camera.py b/exporter/SynthesisFusionAddin/src/UI/Camera.py index 53168fd24..4b8306268 100644 --- a/exporter/SynthesisFusionAddin/src/UI/Camera.py +++ b/exporter/SynthesisFusionAddin/src/UI/Camera.py @@ -9,7 +9,7 @@ @logFailure -def captureThumbnail(size: int = 250) -> str | os.PathLike[str]: +def captureThumbnail(size: int = 250) -> str: """ ## Captures Thumbnail and saves it to a temporary path - needs to be cleared after or on startup - Size: int (Default: 200) : (width & height) diff --git a/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py b/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py index cbdd5f188..b95d6ecbb 100644 --- a/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py +++ b/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py @@ -2,9 +2,6 @@ links the Configuration Command seen when pressing the Synthesis button in the Addins Panel """ -import os -import pathlib -from enum import Enum from typing import Any import adsk.core @@ -15,70 +12,22 @@ from src.Logging import getLogger, logFailure from src.Parser.ExporterOptions import ExporterOptions from src.Parser.SynthesisParser.Parser import Parser -from src.Types import ExportLocation, ExportMode +from src.Types import SELECTABLE_JOINT_TYPES, ExportLocation, ExportMode from src.UI import FileDialogConfig -from src.UI.Configuration.SerialCommand import SerialCommand from src.UI.GamepieceConfigTab import GamepieceConfigTab from src.UI.GeneralConfigTab import GeneralConfigTab from src.UI.JointConfigTab import JointConfigTab -# ====================================== CONFIG COMMAND ====================================== - generalConfigTab: GeneralConfigTab jointConfigTab: JointConfigTab gamepieceConfigTab: GamepieceConfigTab logger = getLogger() -""" -INPUTS_ROOT (adsk.fusion.CommandInputs): - - Provides access to the set of all commandInput UI elements in the panel -""" -INPUTS_ROOT = None - - -# Transition: AARD-1765 -# This should be removed in the config command refactor. Seemingly impossible to type. -def GUID(arg: str | adsk.core.Base) -> str | adsk.core.Base: - """### Will return command object when given a string GUID, or the string GUID of an object (depending on arg value) - - Args: - arg str | object: Either a command input object or command input GUID - - Returns: - str | object: Either a command input object or command input GUID - """ - if type(arg) == str: - object = gm.app.activeDocument.design.findEntityByToken(arg)[0] - return object - else: # type(obj) - return arg.entityToken # type: ignore[union-attr] - - -class JointMotions(Enum): - """### Corresponds to the API JointMotions enum - - Args: - Enum (enum.Enum) - """ - - RIGID = 0 - REVOLUTE = 1 - SLIDER = 2 - CYLINDRICAL = 3 - PIN_SLOT = 4 - PLANAR = 5 - BALL = 6 +INPUTS_ROOT: adsk.core.CommandInputs class ConfigureCommandCreatedHandler(adsk.core.CommandCreatedEventHandler): - """### Start the Command Input Object and define all of the input groups to create our ParserOptions object. - - Notes: - - linked and called from (@ref HButton) and linked - - will be called from (@ref Events.py) - """ - def __init__(self, configure: Any) -> None: super().__init__() @@ -87,22 +36,16 @@ def notify(self, args: adsk.core.CommandCreatedEventArgs) -> None: exporterOptions = ExporterOptions().readFromDesign() or ExporterOptions() cmd = args.command - # Set to false so won't automatically export on switch context cmd.isAutoExecute = False cmd.isExecutedWhenPreEmpted = False - cmd.okButtonText = "Export" # replace default OK text with "export" - cmd.setDialogInitialSize(400, 350) # these aren't working for some reason... - cmd.setDialogMinimumSize(400, 350) # these aren't working for some reason... + cmd.okButtonText = "Export" + cmd.setDialogSize(800, 350) - global INPUTS_ROOT # Global CommandInputs arg + global INPUTS_ROOT INPUTS_ROOT = cmd.commandInputs - # ~~~~~~~~~~~~~~~~ HELP FILE ~~~~~~~~~~~~~~~~ - """ - Sets the small "i" icon in bottom left of the panel. - - This is an HTML file that has a script to redirect to exporter workflow tutorial. - """ - cmd.helpFile = os.path.join(".", "src", "Resources", "HTML", "info.html") + # TODO? + # cmd.helpFile = os.path.join(".", "src", "Resources", "HTML", "info.html") global generalConfigTab generalConfigTab = GeneralConfigTab(args, exporterOptions) @@ -139,10 +82,7 @@ def notify(self, args: adsk.core.CommandCreatedEventArgs) -> None: *gm.app.activeDocument.design.rootComponent.allJoints, *gm.app.activeDocument.design.rootComponent.allAsBuiltJoints, ]: - if ( - joint.jointMotion.jointType in (JointMotions.REVOLUTE.value, JointMotions.SLIDER.value) - and not joint.isSuppressed - ): + if joint.jointMotion.jointType in SELECTABLE_JOINT_TYPES and not joint.isSuppressed: jointConfigTab.addJoint(joint) # Adding saved wheels must take place after joints are added as a result of how the two types are connected. @@ -154,75 +94,6 @@ def notify(self, args: adsk.core.CommandCreatedEventArgs) -> None: if len(fusionJoints): jointConfigTab.addWheel(fusionJoints[0], wheel) - # ~~~~~~~~~~~~~~~~ JOINT SETTINGS ~~~~~~~~~~~~~~~~ - """ - Joint settings group command - """ - - # Transition: AARD-1689 - # Should possibly be implemented later? - - # jointsSettings = a_input.addGroupCommandInput( - # "joints_settings", "Joints Settings" - # ) - # jointsSettings.isExpanded = False - # jointsSettings.isEnabled = True - # jointsSettings.tooltip = "tooltip" # TODO: update tooltip - # joints_settings = jointsSettings.children - - # self.createBooleanInput( - # "kinematic_only", - # "Kinematic Only", - # joints_settings, - # checked=False, - # tooltip="tooltip", # TODO: update tooltip - # enabled=True, - # ) - - # self.createBooleanInput( - # "calculate_limits", - # "Calculate Limits", - # joints_settings, - # checked=True, - # tooltip="tooltip", # TODO: update tooltip - # enabled=True, - # ) - - # self.createBooleanInput( - # "auto_assign_ids", - # "Auto-Assign ID's", - # joints_settings, - # checked=True, - # tooltip="tooltip", # TODO: update tooltip - # enabled=True, - # ) - - # ~~~~~~~~~~~~~~~~ CONTROLLER SETTINGS ~~~~~~~~~~~~~~~~ - """ - Controller settings group command - """ - - # Transition: AARD-1689 - # Should possibly be implemented later? - - # controllerSettings = a_input.addGroupCommandInput( - # "controller_settings", "Controller Settings" - # ) - - # controllerSettings.isExpanded = False - # controllerSettings.isEnabled = True - # controllerSettings.tooltip = "tooltip" # TODO: update tooltip - # controller_settings = controllerSettings.children - - # self.createBooleanInput( # export signals checkbox - # "export_signals", - # "Export Signals", - # controller_settings, - # checked=True, - # tooltip="tooltip", - # enabled=True, - # ) - getAuth() user_info = getUserInfo() apsSettings = INPUTS_ROOT.addTabCommandInput( @@ -230,66 +101,37 @@ def notify(self, args: adsk.core.CommandCreatedEventArgs) -> None: ) apsSettings.tooltip = "Configuration settings for Autodesk Platform Services." - # clear all selections before instantiating handlers. gm.ui.activeSelections.clear() - - # ====================================== EVENT HANDLERS ====================================== - """ - Instantiating all the event handlers - """ - onExecute = ConfigureCommandExecuteHandler() cmd.execute.add(onExecute) - gm.handlers.append(onExecute) # 0 + gm.handlers.append(onExecute) onInputChanged = ConfigureCommandInputChanged(cmd) cmd.inputChanged.add(onInputChanged) - gm.handlers.append(onInputChanged) # 1 + gm.handlers.append(onInputChanged) - onExecutePreview = CommandExecutePreviewHandler(cmd) + onExecutePreview = CommandExecutePreviewHandler() cmd.executePreview.add(onExecutePreview) - gm.handlers.append(onExecutePreview) # 2 + gm.handlers.append(onExecutePreview) onSelect = MySelectHandler(cmd) cmd.select.add(onSelect) - gm.handlers.append(onSelect) # 3 + gm.handlers.append(onSelect) onPreSelect = MyPreSelectHandler(cmd) cmd.preSelect.add(onPreSelect) - gm.handlers.append(onPreSelect) # 4 + gm.handlers.append(onPreSelect) onPreSelectEnd = MyPreselectEndHandler(cmd) cmd.preSelectEnd.add(onPreSelectEnd) - gm.handlers.append(onPreSelectEnd) # 5 + gm.handlers.append(onPreSelectEnd) onDestroy = MyCommandDestroyHandler() cmd.destroy.add(onDestroy) - gm.handlers.append(onDestroy) # 8 + gm.handlers.append(onDestroy) class ConfigureCommandExecuteHandler(adsk.core.CommandEventHandler): - """### Called when Ok is pressed confirming the export - - Process Steps: - - 1. Check for process open in explorer - - 1.5. Open file dialog to allow file location save - - Not always optimal if sending over socket for parse - - 2. Check Socket bind - - 3. Check Socket recv - - if true send data about file location in temp path - - 4. Parse file and focus on unity window - - """ - - def __init__(self) -> None: - super().__init__() - self.current = SerialCommand() - @logFailure(messageBox=True) def notify(self, args: adsk.core.CommandEventArgs) -> None: exporterOptions = ExporterOptions().readFromDesign() @@ -305,14 +147,6 @@ def notify(self, args: adsk.core.CommandEventArgs) -> None: if not savepath: # save was canceled return - - # Transition: AARD-1742 - # With the addition of a 'release' build the fusion exporter will not have permissions within the sourced - # folder. Because of this we cannot use this kind of tmp path anymore. This code was already unused and - # should be removed. - # updatedPath = pathlib.Path(savepath).parent - # if updatedPath != self.current.filePath: - # self.current.filePath = str(updatedPath) else: savepath = processedFileName @@ -361,51 +195,17 @@ def notify(self, args: adsk.core.CommandEventArgs) -> None: class CommandExecutePreviewHandler(adsk.core.CommandEventHandler): - """### Gets an event that is fired when the command has completed gathering the required input and now needs to perform a preview. - - Args: - adsk (CommandEventHandler): Command event handler that a client derives from to handle events triggered by a CommandEvent. - """ - - def __init__(self, cmd: adsk.core.Command) -> None: - super().__init__() - self.cmd = cmd - @logFailure(messageBox=True) def notify(self, args: adsk.core.CommandEventArgs) -> None: - """Notify member called when a command event is triggered - - Args: - args (CommandEventArgs): command event argument - """ jointConfigTab.handlePreviewEvent(args) gamepieceConfigTab.handlePreviewEvent(args) class MySelectHandler(adsk.core.SelectionEventHandler): - """### Event fires when the user selects an entity. - ##### This is different from a preselection where an entity is shown as being available for selection as the mouse passes over the entity. This is the actual selection where the user has clicked the mouse on the entity. - - Args: SelectionEventHandler - """ - - lastInputCmd = None - def __init__(self, cmd: adsk.core.Command) -> None: super().__init__() self.cmd = cmd - # Transition: AARD-1765 - # self.allWheelPreselections = [] # all child occurrences of selections - # self.allGamepiecePreselections = [] # all child gamepiece occurrences of selections - - self.selectedOcc = None # selected occurrence (if there is one) - self.selectedJoint = None # selected joint (if there is one) - - # Transition: AARD-1765 - # self.wheelJointList = [] - self.algorithmicSelection = True - @logFailure(messageBox=True) def traverseAssembly( self, child_occurrences: adsk.fusion.OccurrenceList, jointedOcc: dict[adsk.fusion.Joint, adsk.fusion.Occurrence] @@ -543,11 +343,6 @@ def notify(self, args: adsk.core.SelectionEventArgs) -> None: class MyPreselectEndHandler(adsk.core.SelectionEventHandler): - """### Event fires when the mouse is moved away from an entity that was in a preselect state. - - Args: SelectionEventArgs - """ - def __init__(self, cmd: adsk.core.Command) -> None: super().__init__() self.cmd = cmd @@ -563,25 +358,12 @@ def notify(self, args: adsk.core.SelectionEventArgs) -> None: class ConfigureCommandInputChanged(adsk.core.InputChangedEventHandler): - """### Gets an event that is fired whenever an input value is changed. - - Button pressed, selection made, switching tabs, etc... - - Args: InputChangedEventHandler - """ - def __init__(self, cmd: adsk.core.Command) -> None: super().__init__() self.cmd = cmd - self.allWeights = [None, None] # [lbs, kg] - self.isLbs = True - self.isLbs_f = True @logFailure def reset(self) -> None: - """### Process: - - Reset the mouse icon to default - - Clear active selections - """ self.cmd.setCursor("", 0, 0) gm.ui.activeSelections.clear() @@ -597,14 +379,8 @@ def notify(self, args: adsk.core.InputChangedEventArgs) -> None: class MyCommandDestroyHandler(adsk.core.CommandEventHandler): - """### Gets the event that is fired when the command is destroyed. Globals lists are released and active selections are cleared (when exiting the panel). - - In other words, when the OK or Cancel button is pressed... - - Args: CommandEventHandler - """ - @logFailure(messageBox=True) - def notify(self, args: adsk.core.CommandEventArgs) -> None: + def notify(self, _: adsk.core.CommandEventArgs) -> None: jointConfigTab.reset() gamepieceConfigTab.reset() diff --git a/exporter/SynthesisFusionAddin/src/UI/Configuration/SerialCommand.py b/exporter/SynthesisFusionAddin/src/UI/Configuration/SerialCommand.py deleted file mode 100644 index 61c1e3010..000000000 --- a/exporter/SynthesisFusionAddin/src/UI/Configuration/SerialCommand.py +++ /dev/null @@ -1,104 +0,0 @@ -""" SerialCommand module - -Defines what is generated by the Fusion Command. -Use to be protobuf but can only de-serialize from a filestream strangely. -This is used to store in the userdata. -""" - -import json - -from src.Types import OString - - -# Transition: AARD-1765 -# Will likely be removed later as this is no longer used. Avoiding adding typing for now. -def generateFilePath() -> str: - """Generates a temporary file path that can be used to save the file for exporting - - Example: - - "%appdata%/Roaming/Temp/HellionFiles" - - Returns: - str: file path - """ - tempPath = OString.TempPath("").getPath() # type: ignore - return str(tempPath) - - -class Struct: - """For decoding the dict values into named values""" - - def __init__(self, **entries): # type: ignore - self.__dict__.update(entries) - - -class SerialCommand: - """All of the command inputs combined""" - - def __init__(self): # type: ignore - self.general = General() - self.advanced = Advanced() - - # Transition: AARD-1742 - # With the addition of a 'release' build the fusion exporter will not have permissions within the sourced - # folder. Because of this we cannot use this kind of tmp path anymore. This code was already unused and - # should be removed. - # self.filePath = generateFilePath() - - def toJSON(self) -> str: - """Converts this class into a json object that can be written to the object data - - Returns: - str: json version of this object - """ - return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=1) - - -class General: - """General Options""" - - def __init__(self): # type: ignore - # This is the overall export decision point - self.exportMode = ExportMode.standard - self.RenderType = RenderType.basic3D - self.material = BooleanInput("material", True) - self.joints = BooleanInput("joints", False) - self.rigidGroups = BooleanInput("rigidgroup", False) - # self.wheelType = - self.simpleWheelExport = BooleanInput("simplewheelexport", False) - - -class Advanced: - """Advanced settings in the command input""" - - def __init__(self): # type: ignore - self.friction = BooleanInput("friction", True) - self.density = BooleanInput("density", True) - self.mass = BooleanInput("mass", True) - self.volume = BooleanInput("volume", True) - self.surfaceArea = BooleanInput("surfaceArea", True) - self.com = BooleanInput("com", True) - - -class BooleanInput: - """Class to store the value of a boolean input""" - - def __init__(self, name: str, default: bool): - self.name = name - self.checked = default - - -class ExportMode: - """Export Mode defines the type of export""" - - standard = 0 - VR = 1 - Simulation = 2 - - -class RenderType: - """This will modify the type of material shaders used""" - - basic3D = 0 - URP = 1 - HDRP = 2 diff --git a/exporter/SynthesisFusionAddin/src/UI/Handlers.py b/exporter/SynthesisFusionAddin/src/UI/Handlers.py index 0e60ba36f..b3f11f516 100644 --- a/exporter/SynthesisFusionAddin/src/UI/Handlers.py +++ b/exporter/SynthesisFusionAddin/src/UI/Handlers.py @@ -41,110 +41,3 @@ def __init__(self, button: Any) -> None: def notify(self, _: adsk.core.CommandEventArgs) -> None: self.button.exec_func() - - -""" OLD PALETTE COMMANDS -class HPaletteHTMLEventHandler(adsk.core.HTMLEventHandler): - def __init__(self, palette): - super().__init__() - self.palette = palette - - def notify(self, args) -> None: - ui = adsk.core.Application.get().userInterface - try: - htmlArgs = adsk.core.HTMLEventArgs.cast(args) - - for event in self.palette.events[0]: - if event[0] == htmlArgs.action: - # if Helper.check_solid_open() : - val = event[1](htmlArgs.data) - if val is not None: - # logging.getLogger("HellionFusion.HUI.Handlers").debug( - # f"{htmlArgs.action}: response: {val}" - # ) - htmlArgs.returnData = val - return - else: - htmlArgs.returnData = "" - except: - ui.messageBox("Failed:\n{}".format(traceback.format_exc())) - -""" - -""" These are old functions that mapped the palette commands - -class CustomDocumentSavedHandler(adsk.core.DocumentEventHandler): - def __init__(self): - super().__init__() - - def notify(self, args) -> bool: - eventArgs = adsk.core.DocumentEventArgs.cast(args) - name = Helper.getDocName() - - if name in gm.queue: - connected = Helper.checkAttribute() - if connected and (connected == "True"): - try: - # req = DesignModificationLookup(gm.app.activeDocument.design) - # if req is not None: - # sent = nm.send(req) - # logging.getLogger('HellionFusion.HUI.Handlers.DocumentSaved').debug(f'Sending update with data: {req}') - - design = gm.app.activeDocument.design - name = design.rootComponent.name.rsplit(" ", 1)[0] - version = design.rootComponent.name.rsplit(" ", 1)[1] - - # version comes back the same - this is terrible but it will do - version = int(version[1:]) - version += 1 - version = f"v{version}" - - Helper.addUnityAttribute() - req = Parser(parseOptions=ParseOptions()).parseUpdated(version) - if req is not None: - sent = nm.send(req) - else: - logging.getLogger( - "HellionFusion.HUI.Handlers.DocumentSave" - ).error( - f"Failed to Parse Update or generate request ----- \n {req}" - ) - return True - - except: - gm.ui.messageBox() - logging.getLogger("HellionFusion.HUI.Handlers.DocumentSave").error( - "Failed:\n{}".format(traceback.format_exc()) - ) - - # TODO: add item to queue here - # let the Network manager send them and control how they are sent - # if len(gm.palettes) >= 1: - # palette = gm.ui.palettes.itemById(gm.palettes[0].uid) - # if palette: - # name = Helper.getDocName() - else: - return False - - -class ConnectionPaletteHandler(adsk.core.CustomEventHandler): - def __init__(self): - super().__init__() - - def notify(self, args): - ui = adsk.core.Application.get().userInterface - try: - if ui.activeCommand != "SelectCommand": - ui.commandDefinitions.itemById("SelectCommand").execute() - - if len(gm.palettes) >= 1: - palette = ui.palettes.itemById(gm.palettes[0].uid) - if palette: - res = palette.sendInfoToHTML( - "updateConnection", nm.NetCommand.connected() - ) - except: - if ui: - ui.messageBox("Failed:\n{}".format(traceback.format_exc())) - -""" From db954a401717606ed04089ef2a106bbbc9af1f00 Mon Sep 17 00:00:00 2001 From: BrandonPacewic <92102436+BrandonPacewic@users.noreply.github.com> Date: Thu, 22 Aug 2024 12:00:01 -0700 Subject: [PATCH 2/4] Final changes to `ConfigCommand.py` --- .../src/Parser/ExporterOptions.py | 4 +- .../src/Resources/HTML/info.html | 4 +- exporter/SynthesisFusionAddin/src/Types.py | 2 + .../SynthesisFusionAddin/src/UI/Camera.py | 2 +- .../src/UI/ConfigCommand.py | 290 ++++-------------- .../src/UI/GamepieceConfigTab.py | 2 +- .../SynthesisFusionAddin/src/UI/Handlers.py | 12 + .../src/UI/JointConfigTab.py | 37 ++- 8 files changed, 111 insertions(+), 242 deletions(-) diff --git a/exporter/SynthesisFusionAddin/src/Parser/ExporterOptions.py b/exporter/SynthesisFusionAddin/src/Parser/ExporterOptions.py index 1eb34e9e5..39f6c276b 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/ExporterOptions.py +++ b/exporter/SynthesisFusionAddin/src/Parser/ExporterOptions.py @@ -32,7 +32,7 @@ class ExporterOptions: # Python's `os` module can return `None` when attempting to find the home directory if the # user's computer has conflicting configs of some sort. This has happened and should be accounted # for accordingly. - fileLocation: str | None = field( + fileLocation: str | os.PathLike[str] | None = field( default=(os.getenv("HOME") if platform.system() == "Windows" else os.path.expanduser("~")) ) name: str | None = field(default=None) @@ -52,7 +52,7 @@ class ExporterOptions: compressOutput: bool = field(default=True) exportAsPart: bool = field(default=False) - exportLocation: ExportLocation = field(default=ExportLocation.UPLOAD) + exportLocation: ExportLocation = field(default=ExportLocation.DOWNLOAD) hierarchy: ModelHierarchy = field(default=ModelHierarchy.FusionAssembly) visualQuality: TriangleMeshQualityOptions = field(default=TriangleMeshQualityOptions.LowQualityTriangleMesh) diff --git a/exporter/SynthesisFusionAddin/src/Resources/HTML/info.html b/exporter/SynthesisFusionAddin/src/Resources/HTML/info.html index a44b45f11..759ed2a48 100644 --- a/exporter/SynthesisFusionAddin/src/Resources/HTML/info.html +++ b/exporter/SynthesisFusionAddin/src/Resources/HTML/info.html @@ -2,7 +2,7 @@