From 55188fcc907ae02d2824a97fee68e5d2bbffc6d5 Mon Sep 17 00:00:00 2001 From: BrandonPacewic <92102436+BrandonPacewic@users.noreply.github.com> Date: Tue, 20 Aug 2024 14:46:20 -0700 Subject: [PATCH 1/4] Synthesis Exporter now tracks Fusion's unit system Co-authored-by: PepperLola --- .../src/Parser/ExporterOptions.py | 5 +- exporter/SynthesisFusionAddin/src/Types.py | 32 ++-- .../src/UI/ConfigCommand.py | 7 - .../src/UI/GamepieceConfigTab.py | 78 ++-------- .../src/UI/GeneralConfigTab.py | 137 +++--------------- exporter/SynthesisFusionAddin/src/Util.py | 40 +++++ 6 files changed, 90 insertions(+), 209 deletions(-) create mode 100644 exporter/SynthesisFusionAddin/src/Util.py diff --git a/exporter/SynthesisFusionAddin/src/Parser/ExporterOptions.py b/exporter/SynthesisFusionAddin/src/Parser/ExporterOptions.py index 69e9bbef5d..251a998855 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/ExporterOptions.py +++ b/exporter/SynthesisFusionAddin/src/Parser/ExporterOptions.py @@ -21,7 +21,6 @@ Joint, ModelHierarchy, PhysicalDepth, - PreferredUnits, Wheel, encodeNestedObjects, makeObjectFromJson, @@ -43,10 +42,8 @@ class ExporterOptions: wheels: list[Wheel] = field(default=None) joints: list[Joint] = field(default=None) gamepieces: list[Gamepiece] = field(default=None) - preferredUnits: PreferredUnits = field(default=PreferredUnits.IMPERIAL) - # Always stored in kg regardless of 'preferredUnits' - robotWeight: KG = field(default=0.0) + robotWeight: KG = field(default=KG(0.0)) autoCalcRobotWeight: bool = field(default=False) autoCalcGamepieceWeight: bool = field(default=False) diff --git a/exporter/SynthesisFusionAddin/src/Types.py b/exporter/SynthesisFusionAddin/src/Types.py index 1aca3a5162..0abda446be 100644 --- a/exporter/SynthesisFusionAddin/src/Types.py +++ b/exporter/SynthesisFusionAddin/src/Types.py @@ -3,7 +3,9 @@ import platform from dataclasses import dataclass, field, fields, is_dataclass from enum import Enum, EnumType -from typing import Union, get_origin +from typing import TypeAlias, Union, get_origin + +import adsk.fusion # Not 100% sure what this is for - Brandon JointParentType = Enum("JointParentType", ["ROOT", "END"]) @@ -11,8 +13,16 @@ WheelType = Enum("WheelType", ["STANDARD", "OMNI", "MECANUM"]) SignalType = Enum("SignalType", ["PWM", "CAN", "PASSIVE"]) ExportMode = Enum("ExportMode", ["ROBOT", "FIELD"]) # Dynamic / Static export -PreferredUnits = Enum("PreferredUnits", ["METRIC", "IMPERIAL"]) ExportLocation = Enum("ExportLocation", ["UPLOAD", "DOWNLOAD"]) +UnitSystem = Enum("UnitSystem", ["METRIC", "IMPERIAL"]) + +FUSION_UNIT_SYSTEM: dict[int, Enum] = { + adsk.fusion.DistanceUnits.MillimeterDistanceUnits: UnitSystem.METRIC, + adsk.fusion.DistanceUnits.CentimeterDistanceUnits: UnitSystem.METRIC, + adsk.fusion.DistanceUnits.MeterDistanceUnits: UnitSystem.METRIC, + adsk.fusion.DistanceUnits.InchDistanceUnits: UnitSystem.IMPERIAL, + adsk.fusion.DistanceUnits.FootDistanceUnits: UnitSystem.IMPERIAL, +} @dataclass @@ -72,22 +82,8 @@ class ModelHierarchy(Enum): SingleMesh = 3 -class LBS(float): - """Mass Unit in Pounds.""" - - -class KG(float): - """Mass Unit in Kilograms.""" - - -def toLbs(kgs: float) -> LBS: - return LBS(round(kgs * 2.2062, 2)) - - -def toKg(pounds: float) -> KG: - return KG(round(pounds / 2.2062, 2)) - - +KG: TypeAlias = float +LBS: TypeAlias = float PRIMITIVES = (bool, str, int, float, type(None)) diff --git a/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py b/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py index c50c7feed2..0e83f92136 100644 --- a/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py +++ b/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py @@ -319,12 +319,6 @@ def notify(self, args): selectedJoints, selectedWheels = jointConfigTab.getSelectedJointsAndWheels() selectedGamepieces = gamepieceConfigTab.getGamepieces() - if generalConfigTab.exportMode == ExportMode.ROBOT: - units = generalConfigTab.selectedUnits - else: - assert generalConfigTab.exportMode == ExportMode.FIELD - units = gamepieceConfigTab.selectedUnits - exporterOptions = ExporterOptions( savepath, name, @@ -333,7 +327,6 @@ def notify(self, args): joints=selectedJoints, wheels=selectedWheels, gamepieces=selectedGamepieces, - preferredUnits=units, robotWeight=generalConfigTab.robotWeight, autoCalcRobotWeight=generalConfigTab.autoCalculateWeight, autoCalcGamepieceWeight=gamepieceConfigTab.autoCalculateWeight, diff --git a/exporter/SynthesisFusionAddin/src/UI/GamepieceConfigTab.py b/exporter/SynthesisFusionAddin/src/UI/GamepieceConfigTab.py index 8eb4f80044..9aafb48cd2 100644 --- a/exporter/SynthesisFusionAddin/src/UI/GamepieceConfigTab.py +++ b/exporter/SynthesisFusionAddin/src/UI/GamepieceConfigTab.py @@ -3,13 +3,13 @@ from src.Logging import logFailure from src.Parser.ExporterOptions import ExporterOptions -from src.Types import Gamepiece, PreferredUnits, toKg, toLbs -from src.UI import IconPaths +from src.Types import Gamepiece, UnitSystem from src.UI.CreateCommandInputsHelper import ( createBooleanInput, createTableInput, createTextBoxInput, ) +from src.Util import convertMassUnitsFrom, convertMassUnitsTo, getFusionUnitSystem class GamepieceConfigTab: @@ -19,7 +19,6 @@ class GamepieceConfigTab: gamepieceTable: adsk.core.TableCommandInput previousAutoCalcWeightCheckboxState: bool previousSelectedUnitDropdownIndex: int - currentUnits: PreferredUnits @logFailure def __init__(self, args: adsk.core.CommandCreatedEventArgs, exporterOptions: ExporterOptions) -> None: @@ -37,20 +36,6 @@ def __init__(self, args: adsk.core.CommandCreatedEventArgs, exporterOptions: Exp ) self.previousAutoCalcWeightCheckboxState = exporterOptions.autoCalcGamepieceWeight - self.currentUnits = exporterOptions.preferredUnits - imperialUnits = self.currentUnits == PreferredUnits.IMPERIAL - weightUnitTable = gamepieceTabInputs.addDropDownCommandInput( - "gamepieceWeightUnit", "Unit of Mass", adsk.core.DropDownStyles.LabeledIconDropDownStyle - ) - - # Invisible white space characters are required in the list item name field to make this work. - # I have no idea why, Fusion API needs some special education help - Brandon - weightUnitTable.listItems.add("‎", imperialUnits, IconPaths.massIcons["LBS"]) - weightUnitTable.listItems.add("‎", not imperialUnits, IconPaths.massIcons["KG"]) - weightUnitTable.tooltip = "Unit of mass" - weightUnitTable.tooltipDescription = "
Configure the unit of mass for for the weight calculation." - self.previousSelectedUnitDropdownIndex = int(not imperialUnits) - self.gamepieceTable = createTableInput( "gamepieceTable", "Gamepiece", @@ -62,8 +47,17 @@ def __init__(self, args: adsk.core.CommandCreatedEventArgs, exporterOptions: Exp self.gamepieceTable.addCommandInput( createTextBoxInput("gamepieceNameHeader", "Name", gamepieceTabInputs, "Name", bold=False), 0, 0 ) + fusUnitSystem = getFusionUnitSystem() self.gamepieceTable.addCommandInput( - createTextBoxInput("gamepieceWeightHeader", "Weight", gamepieceTabInputs, "Weight", bold=False), 0, 1 + createTextBoxInput( + "gamepieceWeightHeader", + "Weight", + gamepieceTabInputs, + f"Weight {'(lbs)' if fusUnitSystem is UnitSystem.IMPERIAL else '(kg)'}", + bold=False, + ), + 0, + 1, ) self.gamepieceTable.addCommandInput( createTextBoxInput( @@ -108,10 +102,6 @@ def isVisible(self) -> bool: def isVisible(self, value: bool) -> None: self.gamepieceConfigTab.isVisible = value - @property - def selectedUnits(self) -> PreferredUnits: - return self.currentUnits - @property def autoCalculateWeight(self) -> bool: autoCalcWeightButton: adsk.core.BoolValueCommandInput = self.gamepieceConfigTab.children.itemById( @@ -164,26 +154,13 @@ def addChildOccurrences(childOccurrences: adsk.fusion.OccurrenceList) -> None: frictionCoefficient.valueOne = 0.5 physical = gamepiece.component.getPhysicalProperties(adsk.fusion.CalculationAccuracy.LowCalculationAccuracy) - if self.currentUnits == PreferredUnits.IMPERIAL: - gamepieceMass = toLbs(physical.mass) - else: - gamepieceMass = round(physical.mass, 2) - + gamepieceMass = round(convertMassUnitsFrom(physical.mass), 2) weight = commandInputs.addValueInput( "gamepieceWeight", "Weight Input", "", adsk.core.ValueInput.createByString(str(gamepieceMass)) ) weight.tooltip = "Weight of field element" weight.isEnabled = not self.previousAutoCalcWeightCheckboxState - weightUnitDropdown: adsk.core.DropDownCommandInput = self.gamepieceConfigTab.children.itemById( - "gamepieceWeightUnit" - ) - if weightUnitDropdown.selectedItem.index == 0: - weight.tooltipDescription = "(in pounds)" - else: - assert weightUnitDropdown.selectedItem.index == 1 - weight.tooltipDescription = "(in kilograms)" - row = self.gamepieceTable.rowCount self.gamepieceTable.addCommandInput(gamepieceName, row, 0) self.gamepieceTable.addCommandInput(weight, row, 1) @@ -218,7 +195,7 @@ def getGamepieces(self) -> list[Gamepiece]: gamepieces: list[Gamepiece] = [] for row in range(1, self.gamepieceTable.rowCount): # Row is 1 indexed gamepieceEntityToken = self.selectedGamepieceList[row - 1].entityToken - gamepieceWeight = self.gamepieceTable.getInputAtPosition(row, 1).value + gamepieceWeight = convertMassUnitsTo(self.gamepieceTable.getInputAtPosition(row, 1).value) gamepieceFrictionCoefficient = self.gamepieceTable.getInputAtPosition(row, 2).valueOne gamepieces.append(Gamepiece(gamepieceEntityToken, gamepieceWeight, gamepieceFrictionCoefficient)) @@ -228,14 +205,6 @@ def reset(self) -> None: self.selectedGamepieceEntityIDs.clear() self.selectedGamepieceList.clear() - @logFailure - def updateWeightTableToUnits(self, units: PreferredUnits) -> None: - assert units in {PreferredUnits.METRIC, PreferredUnits.IMPERIAL} - conversionFunc = toKg if units == PreferredUnits.METRIC else toLbs - for row in range(1, self.gamepieceTable.rowCount): # Row is 1 indexed - weightInput: adsk.core.ValueCommandInput = self.gamepieceTable.getInputAtPosition(row, 1) - weightInput.value = conversionFunc(weightInput.value) - @logFailure def calcGamepieceWeights(self) -> None: for row in range(1, self.gamepieceTable.rowCount): # Row is 1 indexed @@ -243,10 +212,7 @@ def calcGamepieceWeights(self) -> None: physical = self.selectedGamepieceList[row - 1].component.getPhysicalProperties( adsk.fusion.CalculationAccuracy.LowCalculationAccuracy ) - if self.currentUnits == PreferredUnits.IMPERIAL: - weightInput.value = toLbs(physical.mass) - else: - weightInput.value = round(physical.mass, 2) + weightInput.value = round(convertMassUnitsFrom(physical.mass), 2) @logFailure def handleInputChanged( @@ -268,20 +234,6 @@ def handleInputChanged( self.previousAutoCalcWeightCheckboxState = autoCalcWeightButton.value - elif commandInput.id == "gamepieceWeightUnit": - weightUnitDropdown = adsk.core.DropDownCommandInput.cast(commandInput) - if weightUnitDropdown.selectedItem.index == self.previousSelectedUnitDropdownIndex: - return - - if weightUnitDropdown.selectedItem.index == 0: - self.currentUnits = PreferredUnits.IMPERIAL - else: - assert weightUnitDropdown.selectedItem.index == 1 - self.currentUnits = PreferredUnits.METRIC - - self.updateWeightTableToUnits(self.currentUnits) - self.previousSelectedUnitDropdownIndex = weightUnitDropdown.selectedItem.index - elif commandInput.id == "gamepieceAddButton": gamepieceAddButton: adsk.core.BoolValueCommandInput = globalCommandInputs.itemById("gamepieceAddButton") gamepieceRemoveButton: adsk.core.BoolValueCommandInput = globalCommandInputs.itemById( diff --git a/exporter/SynthesisFusionAddin/src/UI/GeneralConfigTab.py b/exporter/SynthesisFusionAddin/src/UI/GeneralConfigTab.py index 40a602a406..0a56a76f83 100644 --- a/exporter/SynthesisFusionAddin/src/UI/GeneralConfigTab.py +++ b/exporter/SynthesisFusionAddin/src/UI/GeneralConfigTab.py @@ -2,17 +2,17 @@ import adsk.fusion from src.Logging import logFailure -from src.Parser.ExporterOptions import ( - ExporterOptions, - ExportLocation, - ExportMode, - PreferredUnits, -) -from src.Types import KG, toKg, toLbs -from src.UI import IconPaths -from src.UI.CreateCommandInputsHelper import createBooleanInput, createTableInput +from src.Parser.ExporterOptions import ExporterOptions, ExportLocation, ExportMode +from src.Types import KG, UnitSystem +from src.UI.CreateCommandInputsHelper import createBooleanInput from src.UI.GamepieceConfigTab import GamepieceConfigTab from src.UI.JointConfigTab import JointConfigTab +from src.Util import ( + convertMassUnitsFrom, + convertMassUnitsTo, + designMassCalculation, + getFusionUnitSystem, +) class GeneralConfigTab: @@ -21,7 +21,6 @@ class GeneralConfigTab: previousFrictionOverrideCheckboxState: bool previousSelectedUnitDropdownIndex: int previousSelectedModeDropdownIndex: int - currentUnits: PreferredUnits jointConfigTab: JointConfigTab gamepieceConfigTab: GamepieceConfigTab @@ -57,20 +56,6 @@ def __init__(self, args: adsk.core.CommandCreatedEventArgs, exporterOptions: Exp "
Do you want to upload this mirabuf file to APS, or download it to your local machine?" ) - weightTableInput = createTableInput( - "weightTable", - "Weight Table", - generalTabInputs, - 4, - "2:1:1", - 1, - ) - weightTableInput.tablePresentationStyle = 2 # Transparent background - - weightName = generalTabInputs.addStringValueInput("weightName", "Weight") - weightName.value = "Weight" - weightName.isReadOnly = True - autoCalcWeightButton = createBooleanInput( "autoCalcWeightButton", "Auto Calculate Robot Weight", @@ -80,44 +65,15 @@ def __init__(self, args: adsk.core.CommandCreatedEventArgs, exporterOptions: Exp ) self.previousAutoCalcWeightCheckboxState = exporterOptions.autoCalcRobotWeight - self.currentUnits = exporterOptions.preferredUnits - imperialUnits = self.currentUnits == PreferredUnits.IMPERIAL - if imperialUnits: - # ExporterOptions always contains the metric value - displayWeight = toLbs(exporterOptions.robotWeight) - else: - displayWeight = exporterOptions.robotWeight + displayWeight = convertMassUnitsFrom(exporterOptions.robotWeight) + fusUnitsSystem = getFusionUnitSystem() weightInput = generalTabInputs.addValueInput( "weightInput", - "Weight Input", + f"Weight {'(lbs)' if fusUnitsSystem is UnitSystem.IMPERIAL else '(kg)'}", "", adsk.core.ValueInput.createByReal(displayWeight), ) - weightInput.tooltip = "Robot weight" - weightInput.tooltipDescription = ( - f"(in {'pounds' if self.currentUnits == PreferredUnits.IMPERIAL else 'kilograms'})" - "
This is the weight of the entire robot assembly." - ) - weightInput.isEnabled = not exporterOptions.autoCalcRobotWeight - - weightUnitDropdown = generalTabInputs.addDropDownCommandInput( - "weightUnitDropdown", - "Weight Unit", - adsk.core.DropDownStyles.LabeledIconDropDownStyle, - ) - - # Invisible white space characters are required in the list item name field to make this work. - # I have no idea why, Fusion API needs some special education help - Brandon - weightUnitDropdown.listItems.add("‎", imperialUnits, IconPaths.massIcons["LBS"]) - weightUnitDropdown.listItems.add("‎", not imperialUnits, IconPaths.massIcons["KG"]) - weightUnitDropdown.tooltip = "Unit of Mass" - weightUnitDropdown.tooltipDescription = "
Configure the unit of mass for the weight calculation." - self.previousSelectedUnitDropdownIndex = int(not imperialUnits) - - weightTableInput.addCommandInput(weightName, 0, 0) - weightTableInput.addCommandInput(weightInput, 0, 1) - weightTableInput.addCommandInput(weightUnitDropdown, 0, 2) createBooleanInput( "compressOutputButton", @@ -157,7 +113,7 @@ def __init__(self, args: adsk.core.CommandCreatedEventArgs, exporterOptions: Exp if exporterOptions.exportMode == ExportMode.FIELD: autoCalcWeightButton.isVisible = False exportAsPartButton.isVisible = False - weightInput.isVisible = weightTableInput.isVisible = False + weightInput.isVisible = False frictionOverrideButton.isVisible = frictionCoefficient.isVisible = False @property @@ -185,20 +141,10 @@ def exportAsPart(self) -> bool: ) return exportAsPartButton.value - @property - def selectedUnits(self) -> PreferredUnits: - return self.currentUnits - @property def robotWeight(self) -> KG: - weightInput: adsk.core.ValueCommandInput = self.generalOptionsTab.children.itemById( - "weightTable" - ).getInputAtPosition(0, 1) - if self.currentUnits == PreferredUnits.METRIC: - return KG(weightInput.value) - else: - assert self.currentUnits == PreferredUnits.IMPERIAL - return toKg(weightInput.value) + weightInput: adsk.core.ValueCommandInput = self.generalOptionsTab.children.itemById("weightInput") + return convertMassUnitsTo(weightInput.value) @property def autoCalculateWeight(self) -> bool: @@ -238,7 +184,7 @@ def handleInputChanged(self, args: adsk.core.InputChangedEventArgs) -> None: if commandInput.id == "exportModeDropdown": modeDropdown = adsk.core.DropDownCommandInput.cast(commandInput) autoCalcWeightButton: adsk.core.BoolValueCommandInput = args.inputs.itemById("autoCalcWeightButton") - weightTable: adsk.core.TableCommandInput = args.inputs.itemById("weightTable") + weightInput: adsk.core.TableCommandInput = args.inputs.itemById("weightInput") exportAsPartButton: adsk.core.BoolValueCommandInput = args.inputs.itemById("exportAsPartButton") overrideFrictionButton: adsk.core.BoolValueCommandInput = args.inputs.itemById("frictionOverride") frictionSlider: adsk.core.FloatSliderCommandInput = args.inputs.itemById("frictionCoefficient") @@ -250,7 +196,7 @@ def handleInputChanged(self, args: adsk.core.InputChangedEventArgs) -> None: self.gamepieceConfigTab.isVisible = False autoCalcWeightButton.isVisible = True - weightTable.isVisible = True + weightInput.isVisible = True exportAsPartButton.isVisible = True overrideFrictionButton.isVisible = True frictionSlider.isVisible = overrideFrictionButton.value @@ -260,46 +206,21 @@ def handleInputChanged(self, args: adsk.core.InputChangedEventArgs) -> None: self.gamepieceConfigTab.isVisible = True autoCalcWeightButton.isVisible = False - weightTable.isVisible = False + weightInput.isVisible = False exportAsPartButton.isVisible = False overrideFrictionButton.isVisible = frictionSlider.isVisible = False self.previousSelectedModeDropdownIndex = modeDropdown.selectedItem.index - elif commandInput.id == "weightUnitDropdown": - weightUnitDropdown = adsk.core.DropDownCommandInput.cast(commandInput) - weightTable: adsk.core.TableCommandInput = args.inputs.itemById("weightTable") - weightInput: adsk.core.ValueCommandInput = weightTable.getInputAtPosition(0, 1) - if weightUnitDropdown.selectedItem.index == self.previousSelectedUnitDropdownIndex: - return - - if weightUnitDropdown.selectedItem.index == 0: - self.currentUnits = PreferredUnits.IMPERIAL - weightInput.value = toLbs(weightInput.value) - weightInput.tooltipDescription = ( - "(in pounds)
This is the weight of the entire robot assembly." - ) - else: - assert weightUnitDropdown.selectedItem.index == 1 - self.currentUnits = PreferredUnits.METRIC - weightInput.value = toKg(weightInput.value) - weightInput.tooltipDescription = ( - "(in kilograms)
This is the weight of the entire robot assembly." - ) - - self.previousSelectedUnitDropdownIndex = weightUnitDropdown.selectedItem.index - elif commandInput.id == "autoCalcWeightButton": autoCalcWeightButton = adsk.core.BoolValueCommandInput.cast(commandInput) if autoCalcWeightButton.value == self.previousAutoCalcWeightCheckboxState: return - weightTable: adsk.core.TableCommandInput = args.inputs.itemById("weightTable") - weightInput: adsk.core.ValueCommandInput = weightTable.getInputAtPosition(0, 1) + weightInput: adsk.core.ValueCommandInput = args.inputs.itemById("weightInput") if autoCalcWeightButton.value: - robotMass = designMassCalculation() - weightInput.value = robotMass if self.currentUnits is PreferredUnits.METRIC else toLbs(robotMass) + weightInput.value = designMassCalculation() weightInput.isEnabled = False else: weightInput.isEnabled = True @@ -313,22 +234,4 @@ def handleInputChanged(self, args: adsk.core.InputChangedEventArgs) -> None: return frictionSlider.isVisible = frictionOverrideButton.value - self.previousFrictionOverrideCheckboxState = frictionOverrideButton.value - - -# TODO: Perhaps move this into a different module -@logFailure -def designMassCalculation() -> KG: - app = adsk.core.Application.get() - mass = 0.0 - for body in [x for x in app.activeDocument.design.rootComponent.bRepBodies if x.isLightBulbOn]: - physical = body.getPhysicalProperties(adsk.fusion.CalculationAccuracy.LowCalculationAccuracy) - mass += physical.mass - - for occ in [x for x in app.activeDocument.design.rootComponent.allOccurrences if x.isLightBulbOn]: - for body in [x for x in occ.component.bRepBodies if x.isLightBulbOn]: - physical = body.getPhysicalProperties(adsk.fusion.CalculationAccuracy.LowCalculationAccuracy) - mass += physical.mass - - return KG(round(mass, 2)) diff --git a/exporter/SynthesisFusionAddin/src/Util.py b/exporter/SynthesisFusionAddin/src/Util.py new file mode 100644 index 0000000000..045a900da2 --- /dev/null +++ b/exporter/SynthesisFusionAddin/src/Util.py @@ -0,0 +1,40 @@ +import adsk.core +import adsk.fusion + +from src.Types import FUSION_UNIT_SYSTEM, KG, LBS, UnitSystem + + +def getFusionUnitSystem() -> UnitSystem: + fusDesign = adsk.fusion.Design.cast(adsk.core.Application.get().activeProduct) + return FUSION_UNIT_SYSTEM.get(fusDesign.fusionUnitsManager.distanceDisplayUnits, UnitSystem.METRIC) + + +def convertMassUnitsFrom(input: float) -> float: + """Converts stored Synthesis mass units into user selected Fusion units.""" + unitManager = adsk.fusion.Design.cast(adsk.core.Application.get().activeProduct).fusionUnitsManager + toString = "kg" if getFusionUnitSystem() is UnitSystem.METRIC else "lbmass" + return unitManager.convert(input, "kg", toString) + + +def convertMassUnitsTo(input: float) -> float: + """Converts user selected Fusion mass units into Synthesis units.""" + unitManager = adsk.fusion.Design.cast(adsk.core.Application.get().activeProduct).fusionUnitsManager + fromString = "kg" if getFusionUnitSystem() is UnitSystem.METRIC else "lbmass" + return unitManager.convert(input, fromString, "kg") + + +def designMassCalculation() -> KG | LBS: + """Calculates and returns the total mass of the active design in Fusion units.""" + app = adsk.core.Application.get() + mass = 0.0 + for body in [x for x in app.activeDocument.design.rootComponent.bRepBodies if x.isLightBulbOn]: + physical = body.getPhysicalProperties(adsk.fusion.CalculationAccuracy.LowCalculationAccuracy) + mass += physical.mass + + for occ in [x for x in app.activeDocument.design.rootComponent.allOccurrences if x.isLightBulbOn]: + for body in [x for x in occ.component.bRepBodies if x.isLightBulbOn]: + physical = body.getPhysicalProperties(adsk.fusion.CalculationAccuracy.LowCalculationAccuracy) + mass += physical.mass + + # Internally, Fusion always uses metric units, same as Synthesis + return round(convertMassUnitsFrom(mass), 2) From 1992a75522f2841115af8ebbed003128ddda4dd4 Mon Sep 17 00:00:00 2001 From: BrandonPacewic <92102436+BrandonPacewic@users.noreply.github.com> Date: Tue, 20 Aug 2024 14:51:19 -0700 Subject: [PATCH 2/4] Update conversion function typing --- exporter/SynthesisFusionAddin/src/Util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exporter/SynthesisFusionAddin/src/Util.py b/exporter/SynthesisFusionAddin/src/Util.py index 045a900da2..7384f5a03c 100644 --- a/exporter/SynthesisFusionAddin/src/Util.py +++ b/exporter/SynthesisFusionAddin/src/Util.py @@ -9,14 +9,14 @@ def getFusionUnitSystem() -> UnitSystem: return FUSION_UNIT_SYSTEM.get(fusDesign.fusionUnitsManager.distanceDisplayUnits, UnitSystem.METRIC) -def convertMassUnitsFrom(input: float) -> float: +def convertMassUnitsFrom(input: KG | LBS) -> KG | LBS: """Converts stored Synthesis mass units into user selected Fusion units.""" unitManager = adsk.fusion.Design.cast(adsk.core.Application.get().activeProduct).fusionUnitsManager toString = "kg" if getFusionUnitSystem() is UnitSystem.METRIC else "lbmass" return unitManager.convert(input, "kg", toString) -def convertMassUnitsTo(input: float) -> float: +def convertMassUnitsTo(input: KG | LBS) -> KG | LBS: """Converts user selected Fusion mass units into Synthesis units.""" unitManager = adsk.fusion.Design.cast(adsk.core.Application.get().activeProduct).fusionUnitsManager fromString = "kg" if getFusionUnitSystem() is UnitSystem.METRIC else "lbmass" From d8ef11d7a63b9a4e0764b53bbdc1204d1478186c Mon Sep 17 00:00:00 2001 From: BrandonPacewic <92102436+BrandonPacewic@users.noreply.github.com> Date: Tue, 20 Aug 2024 14:55:08 -0700 Subject: [PATCH 3/4] Fix variable name typo --- exporter/SynthesisFusionAddin/src/UI/GeneralConfigTab.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exporter/SynthesisFusionAddin/src/UI/GeneralConfigTab.py b/exporter/SynthesisFusionAddin/src/UI/GeneralConfigTab.py index 0a56a76f83..46a77996cd 100644 --- a/exporter/SynthesisFusionAddin/src/UI/GeneralConfigTab.py +++ b/exporter/SynthesisFusionAddin/src/UI/GeneralConfigTab.py @@ -67,10 +67,10 @@ def __init__(self, args: adsk.core.CommandCreatedEventArgs, exporterOptions: Exp displayWeight = convertMassUnitsFrom(exporterOptions.robotWeight) - fusUnitsSystem = getFusionUnitSystem() + fusUnitSystem = getFusionUnitSystem() weightInput = generalTabInputs.addValueInput( "weightInput", - f"Weight {'(lbs)' if fusUnitsSystem is UnitSystem.IMPERIAL else '(kg)'}", + f"Weight {'(lbs)' if fusUnitSystem is UnitSystem.IMPERIAL else '(kg)'}", "", adsk.core.ValueInput.createByReal(displayWeight), ) From 82ba010a2b128056eea847725c6958bef6c11fc6 Mon Sep 17 00:00:00 2001 From: BrandonPacewic <92102436+BrandonPacewic@users.noreply.github.com> Date: Tue, 20 Aug 2024 16:43:18 -0700 Subject: [PATCH 4/4] Remove mass icons --- .../src/Resources/kg_icon/16x16-normal.png | Bin 987 -> 0 bytes .../src/Resources/lbs_icon/16x16-normal.png | Bin 1095 -> 0 bytes .../SynthesisFusionAddin/src/UI/IconPaths.py | 5 ----- 3 files changed, 5 deletions(-) delete mode 100644 exporter/SynthesisFusionAddin/src/Resources/kg_icon/16x16-normal.png delete mode 100644 exporter/SynthesisFusionAddin/src/Resources/lbs_icon/16x16-normal.png diff --git a/exporter/SynthesisFusionAddin/src/Resources/kg_icon/16x16-normal.png b/exporter/SynthesisFusionAddin/src/Resources/kg_icon/16x16-normal.png deleted file mode 100644 index 86e8fd3cf8c512ae686162284d8daf2bd9e3c35d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 987 zcmV<110?*3P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D18_-1K~zXfwN*_> zR8bWE?u;{zIyhziWP}k0MTjoS5Ho90V4KKnf`V4&qLqsZ+K1383M!};Lbb7t1kn## zS(I2I*dHMlS%?^xil)wtI=AoK_ulv%UoE0OxbNM2?z#8e@BG}WV59nMQrq2sitf`s zW5ay@mk|eIOu39`)8R*~%Q-lslkCgbQDWa5&hA)!8`MuKWy#X#eD+^J9Vi-5a~f)V z&is9TMVoAtnYQ3>J9wybw^H53J;0#scB(uo6h$tNjj33}tfE zGYdp3fUAuP(Q=Nbfowkz&H%Dp+9CGCl;^Mocz)4w&!@vZrOkjr$t9C;0EqA}n4SkZ z$ACvaEuUoY^Ogtb7^i#!_?`eBPA$%RVfh)TIlo|aO?Je9O$ETsy}+d!AV_AP;=u7T z;K3oFeIKy37`RdkT-*-KO7?hw%hJHjC7Ocx9FV^XXlYO=UO{8eG#-=1m0dvNZUuS^ z32t1qQKKlLF!Tes(5sQfJ#-p1Pp>+Lf^^;8gD^&Jb!!~G2karc{o7!Sw03D6YtD+;g5#uDikU=D17{;(fkBh!?hdKjAC@(x&nn$%)nu0WDbo9W*Mgv(yEMDI`cFjOYQJ3gC`>=89HBUT<+8eP^-R@ zf-o?^I3ze@hh1n7-Pzw=mPqOHP#m@+^z$z ze*yYFYece{g@+a1p9Bt6S-XqNr53#^cL^htnUqY-08?~Lob@BZwjLT~jchJq+{mP% z4YPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1KdeOK~zXf#g<)& zlvNnVf9KtCXV%?yT|bseZ52sVQ1e2}tt?SA6bnhn@NArA-cc^R*qzrUFQ0GvfC2RYlFIB)ncxf?fX&MXDUV@gX zknMtzlVIu+Xc|Wd?gF(1f2z{LZ$oTXrnG@ zfX3l|t+Cn9>zm+L&CeWxb7vKOR!4^Dtj@Xd=`--7HtbjHIH!$rCQMBz7FjtJWngDT zF`<-F$oqLd>f?D{vFp-&9tmAaJHx9x!w$6@aQSgU>Mi(1Qh=R7kd zJO@*@KprYRCCB1Ei1sgB1`T4PPOWVLJT)8MRo|!d>^KQCo>nTZh#@i4HeWiK1)G+_ zSZT%S%Ji3jDFn@ypUh$xRbx0o)=Ie6ow^P!B zQZ(){=((=ya8ZY%2(1FxBtxnPv$%wg?NbCh73IeoxBG8XW{~z8*e50q<{y-_OG% zW8nE01-=7z9)?<7=(G|@4;3~5SheTAxH=5yQ6E!1UJ*$YN72%sN!{q6( z=N*`rloO&qEyrffRa*(2mvpaFU)idGUAPhP2h+ z3dT%?vTX6EA z6gnQ}ydd@d4PU6F{`eUV?1mq{^bEbW8dj~7Q+MF&PgV1BviV6vq4ZjYHpq{J_)a8i zNGi&l#FmvflA)EvUSRn~e=eYK+mKNB2?4tIIj;zYwnDEia}+k{Sxo7%%m1S@606H$uWGnQ zlsYZei{F&W$vI_3MNlK)GSvNk7Nde5xb)vySSJtVAAxB6fdBP@e*uDsOA!D}^mqUO N002ovPDHLkV1nVK0FD3v diff --git a/exporter/SynthesisFusionAddin/src/UI/IconPaths.py b/exporter/SynthesisFusionAddin/src/UI/IconPaths.py index 2804af221a..8b377eb659 100644 --- a/exporter/SynthesisFusionAddin/src/UI/IconPaths.py +++ b/exporter/SynthesisFusionAddin/src/UI/IconPaths.py @@ -32,11 +32,6 @@ "remove": resources + os.path.join("MousePreselectIcons", "mouse-remove-icon.png"), } -massIcons = { - "KG": resources + os.path.join("kg_icon"), # resource folder - "LBS": resources + os.path.join("lbs_icon"), # resource folder -} - signalIcons = { "PWM": resources + os.path.join("PWM_icon"), # resource folder "CAN": resources + os.path.join("CAN_icon"), # resource folder