Skip to content

Commit 629d064

Browse files
committed
Merge branch 'dev' into barclah/codelabs
2 parents ce60af5 + 8d17e1b commit 629d064

File tree

139 files changed

+9353
-1829
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

139 files changed

+9353
-1829
lines changed

exporter/SynthesisFusionAddin/Synthesis.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ def register_ui() -> None:
121121
work_panel,
122122
lambda *_: True, # TODO: Should be redone with various refactors.
123123
ShowAPSAuthCommand.ShowAPSAuthCommandCreatedHandler,
124-
description=f"APS",
124+
description=f"Login to your Autodesk account",
125125
command=True,
126126
)
127127

@@ -132,7 +132,7 @@ def register_ui() -> None:
132132
work_panel,
133133
lambda *_: True,
134134
ShowWebsiteCommand.ShowWebsiteCommandCreatedHandler,
135-
description=f"Website Test",
135+
description=f"Open our tutorials page",
136136
command=True,
137137
)
138138
gm.elements.append(websiteButton)

exporter/SynthesisFusionAddin/src/Parser/ExporterOptions.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,10 @@ def readFromDesign(self) -> "ExporterOptions":
6767
for field in fields(self):
6868
attribute = designAttributes.itemByName(INTERNAL_ID, field.name)
6969
if attribute:
70-
attrJsonData = makeObjectFromJson(field.type, json.loads(attribute.value))
70+
attrJsonData = makeObjectFromJson(type(field.type), json.loads(attribute.value))
7171
setattr(self, field.name, attrJsonData)
7272

73+
self.visualQuality = TriangleMeshQualityOptions.LowQualityTriangleMesh
7374
return self
7475

7576
@logFailure

exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Components.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,12 @@ def _ParseBRep(
188188
) -> None:
189189
meshManager = body.meshManager
190190
calc = meshManager.createMeshCalculator()
191-
calc.setQuality(options.visualQuality)
191+
# Disabling for now. We need the user to be able to adjust this, otherwise it gets locked
192+
# into whatever the default was at the time it first creates the export options.
193+
# calc.setQuality(options.visualQuality)
194+
calc.setQuality(adsk.fusion.TriangleMeshQualityOptions.LowQualityTriangleMesh)
195+
# calc.maxNormalDeviation = 3.14159 * (1.0 / 6.0)
196+
# calc.surfaceTolerance = 0.5
192197
mesh = calc.calculate()
193198

194199
fill_info(trimesh, body)

exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Joints.py

+122-43
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@
4242

4343
logger = getLogger()
4444

45+
AcceptedJointTypes = [
46+
adsk.fusion.JointTypes.RevoluteJointType,
47+
adsk.fusion.JointTypes.SliderJointType,
48+
adsk.fusion.JointTypes.BallJointType,
49+
]
4550

4651
# Need to take in a graphcontainer
4752
# Need to create a new base node for each Joint Instance
@@ -99,57 +104,54 @@ def populateJoints(
99104
_addRigidGroup(joint, assembly)
100105
continue
101106

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

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

109-
# progressDialog.message = f"Exporting Joint configuration {joint.name}"
110-
progressDialog.addJoint(joint.name)
114+
# create the definition
115+
joint_definition = joints.joint_definitions[joint.entityToken]
116+
_addJoint(joint, joint_definition)
111117

112-
# create the definition
113-
joint_definition = joints.joint_definitions[joint.entityToken]
114-
_addJoint(joint, joint_definition)
118+
# create the instance of the single definition
119+
joint_instance = joints.joint_instances[joint.entityToken]
115120

116-
# create the instance of the single definition
117-
joint_instance = joints.joint_instances[joint.entityToken]
121+
for parse_joints in options.joints:
122+
if parse_joints.jointToken == joint.entityToken:
123+
guid = str(uuid.uuid4())
124+
signal = signals.signal_map[guid]
125+
construct_info(joint.name, signal, GUID=guid)
126+
signal.io = signal_pb2.IOType.OUTPUT
118127

119-
for parse_joints in options.joints:
120-
if parse_joints.jointToken == joint.entityToken:
121-
guid = str(uuid.uuid4())
122-
signal = signals.signal_map[guid]
123-
construct_info(joint.name, signal, GUID=guid)
124-
signal.io = signal_pb2.IOType.OUTPUT
128+
# really could just map the enum to a friggin string
129+
if parse_joints.signalType != SignalType.PASSIVE and assembly.dynamic:
130+
if parse_joints.signalType == SignalType.CAN:
131+
signal.device_type = signal_pb2.DeviceType.CANBUS
132+
elif parse_joints.signalType == SignalType.PWM:
133+
signal.device_type = signal_pb2.DeviceType.PWM
125134

126-
# really could just map the enum to a friggin string
127-
if parse_joints.signalType != SignalType.PASSIVE and assembly.dynamic:
128-
if parse_joints.signalType == SignalType.CAN:
129-
signal.device_type = signal_pb2.DeviceType.CANBUS
130-
elif parse_joints.signalType == SignalType.PWM:
131-
signal.device_type = signal_pb2.DeviceType.PWM
135+
motor = joints.motor_definitions[joint.entityToken]
136+
fill_info(motor, joint)
137+
simple_motor = motor.simple_motor
138+
simple_motor.stall_torque = parse_joints.force
139+
simple_motor.max_velocity = parse_joints.speed
140+
simple_motor.braking_constant = 0.8 # Default for now
141+
joint_definition.motor_reference = joint.entityToken
132142

133-
motor = joints.motor_definitions[joint.entityToken]
134-
fill_info(motor, joint)
135-
simple_motor = motor.simple_motor
136-
simple_motor.stall_torque = parse_joints.force
137-
simple_motor.max_velocity = parse_joints.speed
138-
simple_motor.braking_constant = 0.8 # Default for now
139-
joint_definition.motor_reference = joint.entityToken
143+
joint_instance.signal_reference = signal.info.GUID
144+
# else:
145+
# signals.signal_map.remove(guid)
140146

141-
joint_instance.signal_reference = signal.info.GUID
142-
# else:
143-
# signals.signal_map.remove(guid)
147+
_addJointInstance(joint, joint_instance, joint_definition, signals, options)
144148

145-
_addJointInstance(joint, joint_instance, joint_definition, signals, options)
149+
# adds information for joint motion and limits
150+
_motionFromJoint(joint.jointMotion, joint_definition)
146151

147-
# adds information for joint motion and limits
148-
_motionFromJoint(joint.jointMotion, joint_definition)
149-
150-
except:
151-
logger.error("Failed:\n{}".format(traceback.format_exc()))
152-
continue
152+
except:
153+
logger.error("Failed:\n{}".format(traceback.format_exc()))
154+
continue
153155

154156

155157
def _addJoint(joint: adsk.fusion.Joint, joint_definition: joint_pb2.Joint) -> None:
@@ -253,10 +255,10 @@ def _motionFromJoint(fusionMotionDefinition: adsk.fusion.JointMotion, proto_join
253255
0: notImplementedPlaceholder, # this should be ignored
254256
1: fillRevoluteJointMotion,
255257
2: fillSliderJointMotion,
256-
3: notImplementedPlaceholder, # TODO: Implement - Ball Joint at least
258+
3: notImplementedPlaceholder,
257259
4: notImplementedPlaceholder, # TODO: Implement
258260
5: notImplementedPlaceholder, # TODO: Implement
259-
6: notImplementedPlaceholder, # TODO: Implement
261+
6: fillBallJointMotion,
260262
}
261263

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

340342

343+
def fillBallJointMotion(ballMotion: adsk.fusion.BallJointMotion, proto_joint: joint_pb2.Joint) -> None:
344+
"""#### Fill Protobuf ball joint motion data
345+
346+
Args:
347+
ballMotion (adsk.fusion.BallJointMotion): Fusion Ball Joint Data
348+
protoJoint (joint_pb2.Joint): Protobuf joint that is being modified
349+
"""
350+
351+
# proto_joint.joint_motion_type = joint_pb2.JointMotion.REVOLUTE
352+
proto_joint.joint_motion_type = joint_pb2.JointMotion.BALL
353+
customDofs = proto_joint.custom
354+
355+
pitchDof = joint_pb2.DOF()
356+
pitchDof.name = "pitch"
357+
pitchDof.axis.x = ballMotion.pitchDirectionVector.x
358+
pitchDof.axis.y = ballMotion.pitchDirectionVector.y
359+
pitchDof.axis.z = ballMotion.pitchDirectionVector.z
360+
if ballMotion.pitchLimits.isMaximumValueEnabled or ballMotion.pitchLimits.isMinimumValueEnabled:
361+
pitchDof.limits.lower = ballMotion.pitchLimits.minimumValue
362+
pitchDof.limits.upper = ballMotion.pitchLimits.maximumValue
363+
pitchDof.value = ballMotion.pitchValue
364+
customDofs.dofs.append(pitchDof)
365+
366+
yawDof = joint_pb2.DOF()
367+
yawDof.name = "yaw"
368+
yawDof.axis.x = ballMotion.yawDirectionVector.x
369+
yawDof.axis.y = ballMotion.yawDirectionVector.y
370+
yawDof.axis.z = ballMotion.yawDirectionVector.z
371+
if ballMotion.yawLimits.isMaximumValueEnabled or ballMotion.yawLimits.isMinimumValueEnabled:
372+
yawDof.limits.lower = ballMotion.yawLimits.minimumValue
373+
yawDof.limits.upper = ballMotion.yawLimits.maximumValue
374+
yawDof.value = ballMotion.yawValue
375+
customDofs.dofs.append(yawDof)
376+
377+
rollDof = joint_pb2.DOF()
378+
rollDof.name = "roll"
379+
rollDof.axis.x = ballMotion.rollDirectionVector.x
380+
rollDof.axis.y = ballMotion.rollDirectionVector.y
381+
rollDof.axis.z = ballMotion.rollDirectionVector.z
382+
if ballMotion.rollLimits.isMaximumValueEnabled or ballMotion.rollLimits.isMinimumValueEnabled:
383+
rollDof.limits.lower = ballMotion.rollLimits.minimumValue
384+
rollDof.limits.upper = ballMotion.rollLimits.maximumValue
385+
rollDof.value = ballMotion.rollValue
386+
customDofs.dofs.append(rollDof)
387+
388+
# ballMotion.
389+
390+
# dof = proto_joint.rotational.rotational_freedom
391+
392+
# # name
393+
# # axis
394+
# # pivot
395+
# # dynamics
396+
# # limits
397+
# # current value
398+
399+
# dof.name = "Rotational Joint"
400+
401+
# dof.value = revoluteMotion.rotationValue
402+
403+
# if revoluteMotion.rotationLimits:
404+
# dof.limits.lower = revoluteMotion.rotationLimits.minimumValue
405+
# dof.limits.upper = revoluteMotion.rotationLimits.maximumValue
406+
407+
# rotationAxisVector = revoluteMotion.rotationAxisVector
408+
# if rotationAxisVector:
409+
#
410+
# else:
411+
# rotationAxis = revoluteMotion.rotationAxis
412+
# # don't handle 4 for now
413+
# # There is a bug here https://jira.autodesk.com/browse/FUS-80533
414+
# # I have 0 memory of why this is necessary
415+
# dof.axis.x = int(rotationAxis == 0)
416+
# dof.axis.y = int(rotationAxis == 2)
417+
# dof.axis.z = int(rotationAxis == 1)
418+
419+
341420
def notImplementedPlaceholder(*argv: Any) -> None: ...
342421

343422

exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Materials.py

+8
Original file line numberDiff line numberDiff line change
@@ -207,18 +207,26 @@ def getMaterialAppearance(
207207

208208
properties = fusionAppearance.appearanceProperties
209209

210+
roughnessProp = properties.itemById("surface_roughness")
211+
if roughnessProp:
212+
appearance.roughness = roughnessProp.value
213+
210214
# Thank Liam for this.
211215
modelItem = properties.itemById("interior_model")
212216
if modelItem:
213217
matModelType = modelItem.value
214218
baseColor = None
215219

216220
if matModelType == 0:
221+
reflectanceProp = properties.itemById("opaque_f0")
222+
if reflectanceProp:
223+
appearance.metallic = reflectanceProp.value
217224
baseColor = properties.itemById("opaque_albedo").value
218225
if baseColor:
219226
baseColor.opacity = 255
220227
elif matModelType == 1:
221228
baseColor = properties.itemById("metal_f0").value
229+
appearance.metallic = 0.8
222230
if baseColor:
223231
baseColor.opacity = 255
224232
elif matModelType == 2:

exporter/SynthesisFusionAddin/src/Types.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def makeObjectFromJson(objType: type, data: Any) -> Any:
109109
assert is_dataclass(obj) and isinstance(data, dict), "Found unsupported type to decode."
110110
for field in fields(obj):
111111
if field.name in data:
112-
setattr(obj, field.name, makeObjectFromJson(field.type, data[field.name]))
112+
setattr(obj, field.name, makeObjectFromJson(type(field.type), data[field.name]))
113113
else:
114114
setattr(obj, field.name, field.default_factory if field.default_factory is not MISSING else field.default)
115115

exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ def notify(self, args: adsk.core.CommandCreatedEventArgs) -> None:
141141
*gm.app.activeDocument.design.rootComponent.allAsBuiltJoints,
142142
]:
143143
if (
144-
joint.jointMotion.jointType in (JointMotions.REVOLUTE.value, JointMotions.SLIDER.value)
144+
joint.jointMotion.jointType
145+
in (JointMotions.REVOLUTE.value, JointMotions.SLIDER.value, JointMotions.BALL.value)
145146
and not joint.isSuppressed
146147
):
147148
jointConfigTab.addJoint(joint)
@@ -301,7 +302,7 @@ def notify(self, args: adsk.core.CommandEventArgs) -> None:
301302

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

306307
if not savepath:
307308
# save was canceled

exporter/SynthesisFusionAddin/src/UI/GamepieceConfigTab.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from src.Logging import logFailure
55
from src.Parser.ExporterOptions import ExporterOptions
6+
from src.Parser.SynthesisParser.Utilities import guid_occurrence
67
from src.Types import Gamepiece, UnitSystem
78
from src.UI.CreateCommandInputsHelper import (
89
createBooleanInput,
@@ -198,7 +199,7 @@ def removeChildOccurrences(childOccurrences: adsk.fusion.OccurrenceList) -> None
198199
def getGamepieces(self) -> list[Gamepiece]:
199200
gamepieces: list[Gamepiece] = []
200201
for row in range(1, self.gamepieceTable.rowCount): # Row is 1 indexed
201-
gamepieceEntityToken = self.selectedGamepieceList[row - 1].entityToken
202+
gamepieceEntityToken = guid_occurrence(self.selectedGamepieceList[row - 1])
202203
gamepieceWeight = convertMassUnitsTo(self.gamepieceTable.getInputAtPosition(row, 1).value)
203204
gamepieceFrictionCoefficient = self.gamepieceTable.getInputAtPosition(row, 2).valueOne
204205
gamepieces.append(Gamepiece(gamepieceEntityToken, gamepieceWeight, gamepieceFrictionCoefficient))

exporter/SynthesisFusionAddin/src/UI/JointConfigTab.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
createTextBoxInput,
1111
)
1212

13+
from ..Parser.SynthesisParser.Joints import AcceptedJointTypes
14+
1315

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

237+
else:
238+
jointSpeed = commandInputs.addValueInput(
239+
"jointSpeed",
240+
"Speed",
241+
"m",
242+
adsk.core.ValueInput.createByReal(0),
243+
)
244+
jointSpeed.tooltip = "Unavailable"
245+
self.jointConfigTable.addCommandInput(jointSpeed, row, 4)
246+
235247
if synJoint:
236248
jointForceValue = synJoint.force * 100 # Currently a factor of 100 - Should be investigated
237249
else:
@@ -479,7 +491,7 @@ def handleInputChanged(
479491
def handleSelectionEvent(self, args: adsk.core.SelectionEventArgs, selectedJoint: adsk.fusion.Joint) -> None:
480492
selectionInput = args.activeInput
481493
jointType = selectedJoint.jointMotion.jointType
482-
if jointType == adsk.fusion.JointTypes.RevoluteJointType or jointType == adsk.fusion.JointTypes.SliderJointType:
494+
if jointType in AcceptedJointTypes:
483495
if not self.addJoint(selectedJoint):
484496
ui = adsk.core.Application.get().userInterface
485497
result = ui.messageBox(

0 commit comments

Comments
 (0)