Skip to content

Commit

Permalink
Merge branch 'dev' into barclah/codelabs
Browse files Browse the repository at this point in the history
  • Loading branch information
HunterBarclay committed Dec 31, 2024
2 parents ce60af5 + 8d17e1b commit 629d064
Show file tree
Hide file tree
Showing 139 changed files with 9,353 additions and 1,829 deletions.
4 changes: 2 additions & 2 deletions exporter/SynthesisFusionAddin/Synthesis.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def register_ui() -> None:
work_panel,
lambda *_: True, # TODO: Should be redone with various refactors.
ShowAPSAuthCommand.ShowAPSAuthCommandCreatedHandler,
description=f"APS",
description=f"Login to your Autodesk account",
command=True,
)

Expand All @@ -132,7 +132,7 @@ def register_ui() -> None:
work_panel,
lambda *_: True,
ShowWebsiteCommand.ShowWebsiteCommandCreatedHandler,
description=f"Website Test",
description=f"Open our tutorials page",
command=True,
)
gm.elements.append(websiteButton)
3 changes: 2 additions & 1 deletion exporter/SynthesisFusionAddin/src/Parser/ExporterOptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,10 @@ def readFromDesign(self) -> "ExporterOptions":
for field in fields(self):
attribute = designAttributes.itemByName(INTERNAL_ID, field.name)
if attribute:
attrJsonData = makeObjectFromJson(field.type, json.loads(attribute.value))
attrJsonData = makeObjectFromJson(type(field.type), json.loads(attribute.value))
setattr(self, field.name, attrJsonData)

self.visualQuality = TriangleMeshQualityOptions.LowQualityTriangleMesh
return self

@logFailure
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,12 @@ def _ParseBRep(
) -> None:
meshManager = body.meshManager
calc = meshManager.createMeshCalculator()
calc.setQuality(options.visualQuality)
# Disabling for now. We need the user to be able to adjust this, otherwise it gets locked
# into whatever the default was at the time it first creates the export options.
# calc.setQuality(options.visualQuality)
calc.setQuality(adsk.fusion.TriangleMeshQualityOptions.LowQualityTriangleMesh)
# calc.maxNormalDeviation = 3.14159 * (1.0 / 6.0)
# calc.surfaceTolerance = 0.5
mesh = calc.calculate()

fill_info(trimesh, body)
Expand Down
165 changes: 122 additions & 43 deletions exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Joints.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@

logger = getLogger()

AcceptedJointTypes = [
adsk.fusion.JointTypes.RevoluteJointType,
adsk.fusion.JointTypes.SliderJointType,
adsk.fusion.JointTypes.BallJointType,
]

# Need to take in a graphcontainer
# Need to create a new base node for each Joint Instance
Expand Down Expand Up @@ -99,57 +104,54 @@ def populateJoints(
_addRigidGroup(joint, assembly)
continue

# for now if it's not a revolute or slider joint ignore it
if joint.jointMotion.jointType != 1 and joint.jointMotion.jointType != 2:
continue
if joint.jointMotion.jointType in AcceptedJointTypes:
try:
# Fusion has no instances of joints but lets roll with it anyway

try:
# Fusion has no instances of joints but lets roll with it anyway
# progressDialog.message = f"Exporting Joint configuration {joint.name}"
progressDialog.addJoint(joint.name)

# progressDialog.message = f"Exporting Joint configuration {joint.name}"
progressDialog.addJoint(joint.name)
# create the definition
joint_definition = joints.joint_definitions[joint.entityToken]
_addJoint(joint, joint_definition)

# create the definition
joint_definition = joints.joint_definitions[joint.entityToken]
_addJoint(joint, joint_definition)
# create the instance of the single definition
joint_instance = joints.joint_instances[joint.entityToken]

# create the instance of the single definition
joint_instance = joints.joint_instances[joint.entityToken]
for parse_joints in options.joints:
if parse_joints.jointToken == joint.entityToken:
guid = str(uuid.uuid4())
signal = signals.signal_map[guid]
construct_info(joint.name, signal, GUID=guid)
signal.io = signal_pb2.IOType.OUTPUT

for parse_joints in options.joints:
if parse_joints.jointToken == joint.entityToken:
guid = str(uuid.uuid4())
signal = signals.signal_map[guid]
construct_info(joint.name, signal, GUID=guid)
signal.io = signal_pb2.IOType.OUTPUT
# really could just map the enum to a friggin string
if parse_joints.signalType != SignalType.PASSIVE and assembly.dynamic:
if parse_joints.signalType == SignalType.CAN:
signal.device_type = signal_pb2.DeviceType.CANBUS
elif parse_joints.signalType == SignalType.PWM:
signal.device_type = signal_pb2.DeviceType.PWM

# really could just map the enum to a friggin string
if parse_joints.signalType != SignalType.PASSIVE and assembly.dynamic:
if parse_joints.signalType == SignalType.CAN:
signal.device_type = signal_pb2.DeviceType.CANBUS
elif parse_joints.signalType == SignalType.PWM:
signal.device_type = signal_pb2.DeviceType.PWM
motor = joints.motor_definitions[joint.entityToken]
fill_info(motor, joint)
simple_motor = motor.simple_motor
simple_motor.stall_torque = parse_joints.force
simple_motor.max_velocity = parse_joints.speed
simple_motor.braking_constant = 0.8 # Default for now
joint_definition.motor_reference = joint.entityToken

motor = joints.motor_definitions[joint.entityToken]
fill_info(motor, joint)
simple_motor = motor.simple_motor
simple_motor.stall_torque = parse_joints.force
simple_motor.max_velocity = parse_joints.speed
simple_motor.braking_constant = 0.8 # Default for now
joint_definition.motor_reference = joint.entityToken
joint_instance.signal_reference = signal.info.GUID
# else:
# signals.signal_map.remove(guid)

joint_instance.signal_reference = signal.info.GUID
# else:
# signals.signal_map.remove(guid)
_addJointInstance(joint, joint_instance, joint_definition, signals, options)

_addJointInstance(joint, joint_instance, joint_definition, signals, options)
# adds information for joint motion and limits
_motionFromJoint(joint.jointMotion, joint_definition)

# adds information for joint motion and limits
_motionFromJoint(joint.jointMotion, joint_definition)

except:
logger.error("Failed:\n{}".format(traceback.format_exc()))
continue
except:
logger.error("Failed:\n{}".format(traceback.format_exc()))
continue


def _addJoint(joint: adsk.fusion.Joint, joint_definition: joint_pb2.Joint) -> None:
Expand Down Expand Up @@ -253,10 +255,10 @@ def _motionFromJoint(fusionMotionDefinition: adsk.fusion.JointMotion, proto_join
0: notImplementedPlaceholder, # this should be ignored
1: fillRevoluteJointMotion,
2: fillSliderJointMotion,
3: notImplementedPlaceholder, # TODO: Implement - Ball Joint at least
3: notImplementedPlaceholder,
4: notImplementedPlaceholder, # TODO: Implement
5: notImplementedPlaceholder, # TODO: Implement
6: notImplementedPlaceholder, # TODO: Implement
6: fillBallJointMotion,
}

fillJointMotionFunc = fillJointMotionFuncSwitcher.get(fusionMotionDefinition.jointType, notImplementedPlaceholder)
Expand Down Expand Up @@ -338,6 +340,83 @@ def fillSliderJointMotion(sliderMotion: adsk.fusion.SliderJointMotion, proto_joi
dof.value = sliderMotion.slideValue


def fillBallJointMotion(ballMotion: adsk.fusion.BallJointMotion, proto_joint: joint_pb2.Joint) -> None:
"""#### Fill Protobuf ball joint motion data
Args:
ballMotion (adsk.fusion.BallJointMotion): Fusion Ball Joint Data
protoJoint (joint_pb2.Joint): Protobuf joint that is being modified
"""

# proto_joint.joint_motion_type = joint_pb2.JointMotion.REVOLUTE
proto_joint.joint_motion_type = joint_pb2.JointMotion.BALL
customDofs = proto_joint.custom

pitchDof = joint_pb2.DOF()
pitchDof.name = "pitch"
pitchDof.axis.x = ballMotion.pitchDirectionVector.x
pitchDof.axis.y = ballMotion.pitchDirectionVector.y
pitchDof.axis.z = ballMotion.pitchDirectionVector.z
if ballMotion.pitchLimits.isMaximumValueEnabled or ballMotion.pitchLimits.isMinimumValueEnabled:
pitchDof.limits.lower = ballMotion.pitchLimits.minimumValue
pitchDof.limits.upper = ballMotion.pitchLimits.maximumValue
pitchDof.value = ballMotion.pitchValue
customDofs.dofs.append(pitchDof)

yawDof = joint_pb2.DOF()
yawDof.name = "yaw"
yawDof.axis.x = ballMotion.yawDirectionVector.x
yawDof.axis.y = ballMotion.yawDirectionVector.y
yawDof.axis.z = ballMotion.yawDirectionVector.z
if ballMotion.yawLimits.isMaximumValueEnabled or ballMotion.yawLimits.isMinimumValueEnabled:
yawDof.limits.lower = ballMotion.yawLimits.minimumValue
yawDof.limits.upper = ballMotion.yawLimits.maximumValue
yawDof.value = ballMotion.yawValue
customDofs.dofs.append(yawDof)

rollDof = joint_pb2.DOF()
rollDof.name = "roll"
rollDof.axis.x = ballMotion.rollDirectionVector.x
rollDof.axis.y = ballMotion.rollDirectionVector.y
rollDof.axis.z = ballMotion.rollDirectionVector.z
if ballMotion.rollLimits.isMaximumValueEnabled or ballMotion.rollLimits.isMinimumValueEnabled:
rollDof.limits.lower = ballMotion.rollLimits.minimumValue
rollDof.limits.upper = ballMotion.rollLimits.maximumValue
rollDof.value = ballMotion.rollValue
customDofs.dofs.append(rollDof)

# ballMotion.

# dof = proto_joint.rotational.rotational_freedom

# # name
# # axis
# # pivot
# # dynamics
# # limits
# # current value

# dof.name = "Rotational Joint"

# dof.value = revoluteMotion.rotationValue

# if revoluteMotion.rotationLimits:
# dof.limits.lower = revoluteMotion.rotationLimits.minimumValue
# dof.limits.upper = revoluteMotion.rotationLimits.maximumValue

# rotationAxisVector = revoluteMotion.rotationAxisVector
# if rotationAxisVector:
#
# else:
# rotationAxis = revoluteMotion.rotationAxis
# # don't handle 4 for now
# # There is a bug here https://jira.autodesk.com/browse/FUS-80533
# # I have 0 memory of why this is necessary
# dof.axis.x = int(rotationAxis == 0)
# dof.axis.y = int(rotationAxis == 2)
# dof.axis.z = int(rotationAxis == 1)


def notImplementedPlaceholder(*argv: Any) -> None: ...


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,18 +207,26 @@ def getMaterialAppearance(

properties = fusionAppearance.appearanceProperties

roughnessProp = properties.itemById("surface_roughness")
if roughnessProp:
appearance.roughness = roughnessProp.value

# Thank Liam for this.
modelItem = properties.itemById("interior_model")
if modelItem:
matModelType = modelItem.value
baseColor = None

if matModelType == 0:
reflectanceProp = properties.itemById("opaque_f0")
if reflectanceProp:
appearance.metallic = reflectanceProp.value
baseColor = properties.itemById("opaque_albedo").value
if baseColor:
baseColor.opacity = 255
elif matModelType == 1:
baseColor = properties.itemById("metal_f0").value
appearance.metallic = 0.8
if baseColor:
baseColor.opacity = 255
elif matModelType == 2:
Expand Down
2 changes: 1 addition & 1 deletion exporter/SynthesisFusionAddin/src/Types.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def makeObjectFromJson(objType: type, data: Any) -> Any:
assert is_dataclass(obj) and isinstance(data, dict), "Found unsupported type to decode."
for field in fields(obj):
if field.name in data:
setattr(obj, field.name, makeObjectFromJson(field.type, data[field.name]))
setattr(obj, field.name, makeObjectFromJson(type(field.type), data[field.name]))
else:
setattr(obj, field.name, field.default_factory if field.default_factory is not MISSING else field.default)

Expand Down
5 changes: 3 additions & 2 deletions exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,8 @@ def notify(self, args: adsk.core.CommandCreatedEventArgs) -> None:
*gm.app.activeDocument.design.rootComponent.allAsBuiltJoints,
]:
if (
joint.jointMotion.jointType in (JointMotions.REVOLUTE.value, JointMotions.SLIDER.value)
joint.jointMotion.jointType
in (JointMotions.REVOLUTE.value, JointMotions.SLIDER.value, JointMotions.BALL.value)
and not joint.isSuppressed
):
jointConfigTab.addJoint(joint)
Expand Down Expand Up @@ -301,7 +302,7 @@ def notify(self, args: adsk.core.CommandEventArgs) -> None:

processedFileName = gm.app.activeDocument.name.replace(" ", "_")
if generalConfigTab.exportLocation == ExportLocation.DOWNLOAD:
savepath = FileDialogConfig.saveFileDialog(defaultPath=exporterOptions.fileLocation)
savepath = FileDialogConfig.saveFileDialog(defaultPath="~/Documents/")

if not savepath:
# save was canceled
Expand Down
3 changes: 2 additions & 1 deletion exporter/SynthesisFusionAddin/src/UI/GamepieceConfigTab.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from src.Logging import logFailure
from src.Parser.ExporterOptions import ExporterOptions
from src.Parser.SynthesisParser.Utilities import guid_occurrence
from src.Types import Gamepiece, UnitSystem
from src.UI.CreateCommandInputsHelper import (
createBooleanInput,
Expand Down Expand Up @@ -198,7 +199,7 @@ def removeChildOccurrences(childOccurrences: adsk.fusion.OccurrenceList) -> None
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
gamepieceEntityToken = guid_occurrence(self.selectedGamepieceList[row - 1])
gamepieceWeight = convertMassUnitsTo(self.gamepieceTable.getInputAtPosition(row, 1).value)
gamepieceFrictionCoefficient = self.gamepieceTable.getInputAtPosition(row, 2).valueOne
gamepieces.append(Gamepiece(gamepieceEntityToken, gamepieceWeight, gamepieceFrictionCoefficient))
Expand Down
14 changes: 13 additions & 1 deletion exporter/SynthesisFusionAddin/src/UI/JointConfigTab.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
createTextBoxInput,
)

from ..Parser.SynthesisParser.Joints import AcceptedJointTypes


class JointConfigTab:
selectedJointList: list[adsk.fusion.Joint] = []
Expand Down Expand Up @@ -232,6 +234,16 @@ def addJoint(self, fusionJoint: adsk.fusion.Joint, synJoint: Joint | None = None
jointSpeed.tooltip = "Meters per second"
self.jointConfigTable.addCommandInput(jointSpeed, row, 4)

else:
jointSpeed = commandInputs.addValueInput(
"jointSpeed",
"Speed",
"m",
adsk.core.ValueInput.createByReal(0),
)
jointSpeed.tooltip = "Unavailable"
self.jointConfigTable.addCommandInput(jointSpeed, row, 4)

if synJoint:
jointForceValue = synJoint.force * 100 # Currently a factor of 100 - Should be investigated
else:
Expand Down Expand Up @@ -479,7 +491,7 @@ def handleInputChanged(
def handleSelectionEvent(self, args: adsk.core.SelectionEventArgs, selectedJoint: adsk.fusion.Joint) -> None:
selectionInput = args.activeInput
jointType = selectedJoint.jointMotion.jointType
if jointType == adsk.fusion.JointTypes.RevoluteJointType or jointType == adsk.fusion.JointTypes.SliderJointType:
if jointType in AcceptedJointTypes:
if not self.addJoint(selectedJoint):
ui = adsk.core.Application.get().userInterface
result = ui.messageBox(
Expand Down
Loading

0 comments on commit 629d064

Please sign in to comment.