From 5a41c6454af2dccc91fc641a6138bfbdd616aaea Mon Sep 17 00:00:00 2001 From: bartool Date: Wed, 21 Sep 2022 21:50:43 +0200 Subject: [PATCH] save plugins Fusion 360 --- ControllByPs4/.env | 1 + ControllByPs4/.vscode/launch.json | 20 ++ ControllByPs4/.vscode/settings.json | 5 + ControllByPs4/ControllByPs4 copy.py | 145 +++++++++++++ ControllByPs4/ControllByPs4.manifest | 13 ++ ControllByPs4/ControllByPs4.py | 24 +++ .../__pycache__/config.cpython-39.pyc | Bin 0 -> 320 bytes ControllByPs4/commands/__init__.py | 29 +++ .../__pycache__/__init__.cpython-39.pyc | Bin 0 -> 534 bytes ControllByPs4/commands/backend/__init__.py | 0 .../__pycache__/__init__.cpython-39.pyc | Bin 0 -> 164 bytes .../__pycache__/backend.cpython-39.pyc | Bin 0 -> 5036 bytes ControllByPs4/commands/backend/backend.py | 178 ++++++++++++++++ .../commands/commandDialog/__init__.py | 0 .../__pycache__/__init__.cpython-39.pyc | Bin 0 -> 170 bytes .../__pycache__/entry.cpython-39.pyc | Bin 0 -> 3852 bytes ControllByPs4/commands/commandDialog/entry.py | 190 +++++++++++++++++ .../commandDialog/resources/16x16.png | Bin 0 -> 415 bytes .../commandDialog/resources/32x32.png | Bin 0 -> 701 bytes .../commandDialog/resources/64x64.png | Bin 0 -> 1077 bytes ControllByPs4/config.py | 21 ++ ControllByPs4/lib/fusion360utils/__init__.py | 2 + .../__pycache__/__init__.cpython-39.pyc | Bin 0 -> 219 bytes .../__pycache__/event_utils.cpython-39.pyc | Bin 0 -> 2894 bytes .../__pycache__/general_utils.cpython-39.pyc | Bin 0 -> 1672 bytes .../lib/fusion360utils/event_utils.py | 88 ++++++++ .../lib/fusion360utils/general_utils.py | 64 ++++++ demo/.env | 1 + demo/.vscode/launch.json | 20 ++ demo/.vscode/settings.json | 6 + demo/demo.manifest | 10 + demo/demo.py | 58 ++++++ eyeCameraTest/.env | 1 + eyeCameraTest/.vscode/launch.json | 20 ++ eyeCameraTest/.vscode/settings.json | 5 + eyeCameraTest/eyeCameraTest.manifest | 10 + eyeCameraTest/eyeCameraTest.py | 27 +++ rotate_Test/.env | 1 + rotate_Test/.vscode/launch.json | 20 ++ rotate_Test/.vscode/settings.json | 5 + rotate_Test/rotate_Test.manifest | 10 + rotate_Test/rotate_Test.py | 58 ++++++ tamplate/.env | 1 + tamplate/.vscode/launch.json | 20 ++ tamplate/.vscode/settings.json | 5 + tamplate/commands/__init__.py | 30 +++ tamplate/commands/commandDialog/__init__.py | 0 tamplate/commands/commandDialog/entry.py | 158 ++++++++++++++ .../commandDialog/resources/16x16.png | Bin 0 -> 415 bytes .../commandDialog/resources/32x32.png | Bin 0 -> 701 bytes .../commandDialog/resources/64x64.png | Bin 0 -> 1077 bytes tamplate/commands/paletteSend/__init__.py | 0 tamplate/commands/paletteSend/entry.py | 149 ++++++++++++++ .../commands/paletteSend/resources/16x16.png | Bin 0 -> 474 bytes .../commands/paletteSend/resources/32x32.png | Bin 0 -> 1067 bytes .../commands/paletteSend/resources/64x64.png | Bin 0 -> 1972 bytes tamplate/commands/paletteShow/__init__.py | 0 tamplate/commands/paletteShow/entry.py | 193 ++++++++++++++++++ .../commands/paletteShow/resources/16x16.png | Bin 0 -> 340 bytes .../commands/paletteShow/resources/32x32.png | Bin 0 -> 587 bytes .../commands/paletteShow/resources/64x64.png | Bin 0 -> 1165 bytes .../paletteShow/resources/html/index.html | 39 ++++ .../resources/html/static/palette.js | 48 +++++ tamplate/config.py | 21 ++ tamplate/lib/fusion360utils/__init__.py | 2 + tamplate/lib/fusion360utils/event_utils.py | 88 ++++++++ tamplate/lib/fusion360utils/general_utils.py | 64 ++++++ tamplate/tamplate.manifest | 13 ++ tamplate/tamplate.py | 24 +++ zoom_test/.env | 1 + zoom_test/.vscode/launch.json | 20 ++ zoom_test/.vscode/settings.json | 5 + zoom_test/zoom_test.manifest | 10 + zoom_test/zoom_test.py | 65 ++++++ 74 files changed, 1988 insertions(+) create mode 100644 ControllByPs4/.env create mode 100644 ControllByPs4/.vscode/launch.json create mode 100644 ControllByPs4/.vscode/settings.json create mode 100644 ControllByPs4/ControllByPs4 copy.py create mode 100644 ControllByPs4/ControllByPs4.manifest create mode 100644 ControllByPs4/ControllByPs4.py create mode 100644 ControllByPs4/__pycache__/config.cpython-39.pyc create mode 100644 ControllByPs4/commands/__init__.py create mode 100644 ControllByPs4/commands/__pycache__/__init__.cpython-39.pyc create mode 100644 ControllByPs4/commands/backend/__init__.py create mode 100644 ControllByPs4/commands/backend/__pycache__/__init__.cpython-39.pyc create mode 100644 ControllByPs4/commands/backend/__pycache__/backend.cpython-39.pyc create mode 100644 ControllByPs4/commands/backend/backend.py create mode 100644 ControllByPs4/commands/commandDialog/__init__.py create mode 100644 ControllByPs4/commands/commandDialog/__pycache__/__init__.cpython-39.pyc create mode 100644 ControllByPs4/commands/commandDialog/__pycache__/entry.cpython-39.pyc create mode 100644 ControllByPs4/commands/commandDialog/entry.py create mode 100644 ControllByPs4/commands/commandDialog/resources/16x16.png create mode 100644 ControllByPs4/commands/commandDialog/resources/32x32.png create mode 100644 ControllByPs4/commands/commandDialog/resources/64x64.png create mode 100644 ControllByPs4/config.py create mode 100644 ControllByPs4/lib/fusion360utils/__init__.py create mode 100644 ControllByPs4/lib/fusion360utils/__pycache__/__init__.cpython-39.pyc create mode 100644 ControllByPs4/lib/fusion360utils/__pycache__/event_utils.cpython-39.pyc create mode 100644 ControllByPs4/lib/fusion360utils/__pycache__/general_utils.cpython-39.pyc create mode 100644 ControllByPs4/lib/fusion360utils/event_utils.py create mode 100644 ControllByPs4/lib/fusion360utils/general_utils.py create mode 100644 demo/.env create mode 100644 demo/.vscode/launch.json create mode 100644 demo/.vscode/settings.json create mode 100644 demo/demo.manifest create mode 100644 demo/demo.py create mode 100644 eyeCameraTest/.env create mode 100644 eyeCameraTest/.vscode/launch.json create mode 100644 eyeCameraTest/.vscode/settings.json create mode 100644 eyeCameraTest/eyeCameraTest.manifest create mode 100644 eyeCameraTest/eyeCameraTest.py create mode 100644 rotate_Test/.env create mode 100644 rotate_Test/.vscode/launch.json create mode 100644 rotate_Test/.vscode/settings.json create mode 100644 rotate_Test/rotate_Test.manifest create mode 100644 rotate_Test/rotate_Test.py create mode 100644 tamplate/.env create mode 100644 tamplate/.vscode/launch.json create mode 100644 tamplate/.vscode/settings.json create mode 100644 tamplate/commands/__init__.py create mode 100644 tamplate/commands/commandDialog/__init__.py create mode 100644 tamplate/commands/commandDialog/entry.py create mode 100644 tamplate/commands/commandDialog/resources/16x16.png create mode 100644 tamplate/commands/commandDialog/resources/32x32.png create mode 100644 tamplate/commands/commandDialog/resources/64x64.png create mode 100644 tamplate/commands/paletteSend/__init__.py create mode 100644 tamplate/commands/paletteSend/entry.py create mode 100644 tamplate/commands/paletteSend/resources/16x16.png create mode 100644 tamplate/commands/paletteSend/resources/32x32.png create mode 100644 tamplate/commands/paletteSend/resources/64x64.png create mode 100644 tamplate/commands/paletteShow/__init__.py create mode 100644 tamplate/commands/paletteShow/entry.py create mode 100644 tamplate/commands/paletteShow/resources/16x16.png create mode 100644 tamplate/commands/paletteShow/resources/32x32.png create mode 100644 tamplate/commands/paletteShow/resources/64x64.png create mode 100644 tamplate/commands/paletteShow/resources/html/index.html create mode 100644 tamplate/commands/paletteShow/resources/html/static/palette.js create mode 100644 tamplate/config.py create mode 100644 tamplate/lib/fusion360utils/__init__.py create mode 100644 tamplate/lib/fusion360utils/event_utils.py create mode 100644 tamplate/lib/fusion360utils/general_utils.py create mode 100644 tamplate/tamplate.manifest create mode 100644 tamplate/tamplate.py create mode 100644 zoom_test/.env create mode 100644 zoom_test/.vscode/launch.json create mode 100644 zoom_test/.vscode/settings.json create mode 100644 zoom_test/zoom_test.manifest create mode 100644 zoom_test/zoom_test.py diff --git a/ControllByPs4/.env b/ControllByPs4/.env new file mode 100644 index 0000000..6aedf1e --- /dev/null +++ b/ControllByPs4/.env @@ -0,0 +1 @@ +PYTHONPATH=C:/Users/bartool/AppData/Local/Autodesk/webdeploy/production/9209df45963e1599ff476303834125d21fd43de4/Api/Python/packages diff --git a/ControllByPs4/.vscode/launch.json b/ControllByPs4/.vscode/launch.json new file mode 100644 index 0000000..1c69300 --- /dev/null +++ b/ControllByPs4/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + "version": "0.2.0", + "configurations": [{ + "name": "Python: Attach", + "type": "python", + "request": "attach", + "pathMappings": [{ + "localRoot": "${workspaceRoot}", + "remoteRoot": "${workspaceRoot}" + }], + "osx": { + "filePath": "${file}" + }, + "windows": { + "filePath": "${file}" + }, + "port": 9000, + "host": "localhost" + }] +} \ No newline at end of file diff --git a/ControllByPs4/.vscode/settings.json b/ControllByPs4/.vscode/settings.json new file mode 100644 index 0000000..1c5eab8 --- /dev/null +++ b/ControllByPs4/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "python.autoComplete.extraPaths": ["C:/Users/bartool/AppData/Roaming/Autodesk/Autodesk Fusion 360/API/Python/defs"], + "python.analysis.extraPaths": ["C:/Users/bartool/AppData/Roaming/Autodesk/Autodesk Fusion 360/API/Python/defs"], + "python.pythonPath": "C:/Users/bartool/AppData/Local/Autodesk/webdeploy/production/9209df45963e1599ff476303834125d21fd43de4/Python/python.exe" +} \ No newline at end of file diff --git a/ControllByPs4/ControllByPs4 copy.py b/ControllByPs4/ControllByPs4 copy.py new file mode 100644 index 0000000..b1fe956 --- /dev/null +++ b/ControllByPs4/ControllByPs4 copy.py @@ -0,0 +1,145 @@ +# Assuming you have not changed the general structure of the template no modification is needed in this file. +# from . import commands +from tkinter import E +from .lib import fusion360utils as futil +import threading +import adsk.core +import adsk.fusion +import adsk.cam +import traceback +import json + + +app = None +ui = adsk.core.UserInterface.cast(None) +handlers = [] +stopFlag = None +myCustomEvent = 'MyCustomEventId' +customEvent = None + + +# The event handler that responds to the custom event being fired. +class ThreadEventHandler(adsk.core.CustomEventHandler): + def __init__(self): + super().__init__() + self.viewport = app.activeViewport + + def notify(self, args: adsk.core.CustomEventArgs): + global app + try: + # Make sure a command isn't running before changes are made. + activeCmd = ui.activeCommand + if activeCmd != 'SelectCommand': + ui.commandDefinitions.itemById('SelectCommand').execute() + + camera = self.viewport.camera + eye = camera.eye + target = camera.target + up = camera.upVector + zoom = camera.viewExtents + + front = eye.vectorTo(target) + right = up.crossProduct(front) + rotate_matrix = adsk.core.Matrix3D.create() + rotate_matrix.setWithCoordinateSystem(target, right, front, up) + mat = rotate_matrix.asArray() + + # Get the value from the JSON data passed through the event. + eventArgs = json.loads(args.additionalInfo) + + X_radians = float(eventArgs['X_rotation']) + if X_radians: + rotate_matrix.setToRotation(X_radians, front, target) + eye.transformBy(rotate_matrix) + up.transformBy(rotate_matrix) + + Y_radians = float(eventArgs['Y_rotation']) + if Y_radians: + rotate_matrix.setToRotation(Y_radians, right, target) + eye.transformBy(rotate_matrix) + up.transformBy(rotate_matrix) + + Z_radians = float(eventArgs['Z_rotation']) + if Z_radians: + rotate_matrix.setToRotation(Z_radians, up, target) + eye.transformBy(rotate_matrix) + up.transformBy(rotate_matrix) + + X_pan = float(eventArgs['X_pan']) + Y_pan = float(eventArgs['Y_pan']) + Z_pan = float(eventArgs['Z_pan']) + if any([X_pan, Z_pan]): + move_vector = adsk.core.Vector3D.create(X_pan, 0, Z_pan) + move_vector.transformBy(rotate_matrix) + eye.translateBy(move_vector) + target.translateBy(move_vector) + + if Y_pan: + zoom = zoom + Y_pan * 10 + + camera.isSmoothTransition = True + camera.eye = eye + camera.upVector = up + camera.target = target + camera.viewExtents = zoom + app.activeViewport.camera = camera + app.activeViewport.refresh() + + except: + if ui: + ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) + + def rotate(self, X_radians: float, Y_radians: float, Z_radians: float): + pass + + +# The class for the new thread. +class MyThread(threading.Thread): + def __init__(self, event): + threading.Thread.__init__(self) + self.stopped = event + + def run(self): + # Every five seconds fire a custom event, passing a random number. + while not self.stopped.wait(2): + args = {'X_rotation': 0.0, 'Y_rotation': 0.0, 'Z_rotation': 0.0, + 'X_pan': 0.0, 'Y_pan': 1.0, 'Z_pan': 0.0} + app.fireCustomEvent(myCustomEvent, json.dumps(args)) + + +def run(context): + global ui + global app + try: + app = adsk.core.Application.get() + ui = app.userInterface + + # Register the custom event and connect the handler. + global customEvent + customEvent = app.registerCustomEvent(myCustomEvent) + onThreadEvent = ThreadEventHandler() + customEvent.add(onThreadEvent) + handlers.append(onThreadEvent) + + # Create a new thread for the other processing. + global stopFlag + stopFlag = threading.Event() + myThread = MyThread(stopFlag) + myThread.start() + except: + futil.handle_error('run') + if ui: + ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) + + +def stop(context): + try: + if handlers.count: + customEvent.remove(handlers[0]) + stopFlag.set() + app.unregisterCustomEvent(myCustomEvent) + ui.messageBox('Stop addin') + except: + futil.handle_error('stop') + if ui: + ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) diff --git a/ControllByPs4/ControllByPs4.manifest b/ControllByPs4/ControllByPs4.manifest new file mode 100644 index 0000000..39d8a75 --- /dev/null +++ b/ControllByPs4/ControllByPs4.manifest @@ -0,0 +1,13 @@ +{ + "autodeskProduct": "Fusion360", + "type": "addin", + "id": "1a7fc1eb-71fd-42da-86f0-a7e640d647d0", + "author": "", + "description": { + "": "" + }, + "version": "", + "runOnStartup": false, + "supportedOS": "windows|mac", + "editEnabled": true +} \ No newline at end of file diff --git a/ControllByPs4/ControllByPs4.py b/ControllByPs4/ControllByPs4.py new file mode 100644 index 0000000..938ad75 --- /dev/null +++ b/ControllByPs4/ControllByPs4.py @@ -0,0 +1,24 @@ +# Assuming you have not changed the general structure of the template no modification is needed in this file. +from . import commands +from .lib import fusion360utils as futil + + +def run(context): + try: + # This will run the start function in each of your commands as defined in commands/__init__.py + commands.start() + + except: + futil.handle_error('run') + + +def stop(context): + try: + # Remove all of the event handlers your app has created + futil.clear_handlers() + + # This will run the start function in each of your commands as defined in commands/__init__.py + commands.stop() + + except: + futil.handle_error('stop') diff --git a/ControllByPs4/__pycache__/config.cpython-39.pyc b/ControllByPs4/__pycache__/config.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ad1b1d44b6183eeacb781832440d4cb0fd0e5538 GIT binary patch literal 320 zcmYk2%}T>S6oqFx`D?Wc!3S_#7e-Kuh=}_jyY!W2 z>&jPfBqK7xt$rME#m$H<@GD@gDjY0{EO$w)ybLp9(+nc>WT zx>ZJ#%9V0nQo-u9V#=mP+cyp&c~LS#@W>0pyO_jYG{gJBLzH;&^RGJ)Y1QbNzwi&x z4)y6C-_zi75p_w+*DRC5Z92K)wVQ85!Rxc>sT=TGw!AF;E)nO8jMsUwJZU=RTveQI SN_M^bhHx|-%dififqnpsQC0;2 literal 0 HcmV?d00001 diff --git a/ControllByPs4/commands/__init__.py b/ControllByPs4/commands/__init__.py new file mode 100644 index 0000000..195567b --- /dev/null +++ b/ControllByPs4/commands/__init__.py @@ -0,0 +1,29 @@ +# Here you define the commands that will be added to your add-in. + +# TODO Import the modules corresponding to the commands you created. +# If you want to add an additional command, duplicate one of the existing directories and import it here. +# You need to use aliases (import "entry" as "my_module") assuming you have the default module named "entry". +import imp +from .commandDialog import entry as commandDialog +from .backend import backend + +# TODO add your imported modules to this list. +# Fusion will automatically call the start() and stop() functions. +commands = [ + commandDialog, + backend +] + + +# Assumes you defined a "start" function in each of your modules. +# The start function will be run when the add-in is started. +def start(): + for command in commands: + command.start() + + +# Assumes you defined a "stop" function in each of your modules. +# The stop function will be run when the add-in is stopped. +def stop(): + for command in commands: + command.stop() diff --git a/ControllByPs4/commands/__pycache__/__init__.cpython-39.pyc b/ControllByPs4/commands/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b0d2de9536c463437f45d46bda930622c0914478 GIT binary patch literal 534 zcmbV|u};G<5QguZq%n{(Ar_t>LZV0@22>%SU8yQ{i;AKUhZ0EQVy8nS*mw{ayYN6+ znfeMH5a-Z}&YX0=@6Oim&yL#dZJ_uZ9mY!w;L9|d!Kk^U)Ljw*0y79eFkxkwvjEZ5 zc4p;PU?C)!SQ8f5!V#@E2pr)GPHRix2>h)DIly3nq(0V8Qk1Hq!o7>)r=$?E*9^=wQ|V7XR1X@ZR=7_6{oTx{goZldL##we;1mG@77kDPwVyyvY$qooG9~I%8)g# k4O(NcVQM}?8RwdJb17z7a$yMcE(u2uJ%=ItwmEly0Qlc%4FCWD literal 0 HcmV?d00001 diff --git a/ControllByPs4/commands/backend/__init__.py b/ControllByPs4/commands/backend/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ControllByPs4/commands/backend/__pycache__/__init__.cpython-39.pyc b/ControllByPs4/commands/backend/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..be20c21a3b8b481aed4a2e5372972dd2854c429b GIT binary patch literal 164 zcmYe~<>g`kfY!%~M8Bmm; zm6}{qtY1)Bl98XMpH^C&nV)BDW}xq!pI1_ppOfQM8BlBzlboNMo0ykU9FvrooSmAN h5)&VvnU`4-AFo$Xd5gm)H$SB`C)EyQ#b+R9000T7C}aQt literal 0 HcmV?d00001 diff --git a/ControllByPs4/commands/backend/__pycache__/backend.cpython-39.pyc b/ControllByPs4/commands/backend/__pycache__/backend.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9099fe9389fda1e36cd7319b2002805717f909bb GIT binary patch literal 5036 zcmai2&2JmW72j_zmmi`iS&r=3rXAZYlU8<{A_da4h%6_KQCKk|<-@Gg?V7Wa$dJ4A z?9j2;We>H19C`_QDo__7fnL&6|A77_b8Rm^73i^tw!b&Kq$tHsmYBD1XXeekdGkIQ zR4Sf^=U?|;YyaUTP5TFZEIt-K-bPFQ3BWX__q4v=(sja(p3yg225^&EJ+p7MY}Ie~ zoR))eyH{wr>Rrs=Uj8n%N~*uyDl?~53EghByELgywP0B+ck8VcW(TXR&^pE3*4n-n zoZi=3FEK4xM>~Ud7VTxUb7<#(uCXHXo@mTd>s)wjwi@Uwu`>F~^S+DdtFS8is-e@p zgjuh!C02W)wJx(|R>%7avv;)S$}^l)YwFSr_NelNcN%*^_#d&8s?N3XweeJDD; zWP5b_qfYpFV=ImXk9)n4H|_`R&%%hw<*lF}@_>flc^F3G7L#iq4p<;UOin})i6rlD z(|(H&?L|*=9U#wK^$G1%j?=qMmG-cBtN>>j{ALZl-$eZ zHG6Li4tWWjTqKr=H%%X1{)Y2x%-AAUE!n5Kd|^V_kc!2L*+j3U?K5DZHp~Tj8F<9fg+^UQl?MWY~1K zM`s!*4$z2V(GiCm8ynL5#OJXH1e8j8cNg&15pI9t4}wVAce7WEUd@WM_eck&*^Bq3 zyLJ1fzrA_;9cgtFEM@oNfF-gTFxH{9gWj!ZF9r$v1#SAl`@5UFx8C2TO^@)_5sppo zY;M!0>eZrG)8rM%j@JQXF(kF#gv5D`Iu%%^5r>YqcX%0iLcN+^)5~UApZ!LcPRK(U zLav}28F8~n8W+Kad|!IL-;dd_M|j!y9}I(DHlkDo*Upm9q}7gjD3`W|iHQ4ZMaA29 ziK9xcsO_-V^Zf;WN$EK;&0T;7T0&~#f?w6s#>cUTM(Ii32KXl1e5x~x*<_iaOF!m3 zHCchV=qV~&^`IO@xpu-$e5;wRVc#P&6-L)gHQypt<3$WLZB7n76O0)Q2GD`F=sXO` z5e;H4r28<(c$p?D3C!#1Tn+rqyQXfg7 zbzxjEE&Vf-U&5C$F_}KqCl)!JR3o1@HdC`(7+Zku*aj?)9YAkfNUcdJCG&JsXHrgG zU`0`x#f`C-dXweUPKznVrxw=pCiST{E{T=NDh&G+=9k4^zuo-1F3zO2w7!q?VEsQTiJYC((i$_<`qUh+q${&?;A}6aE9z|a99ss} zU(-Um%!;epX>D9!UTXU1Qrv)F0H3ChGXlDpWBM2q=erkthv1|^_x7{b?vSe8P`=vX_mKTWhd+*L~LadfRnCpibVVr0n%@NngG%f zjjsbdBaPl2dG7|DUdZ0`elu=fk;bqiE17ENE6I8uRBncQ6sq9%66tnC*uQaz=vxRM zh3%mTIjOgF+A2ItGdv8XBM>-3n8tAM5jcyvERm7C^GLwMVU35Xb2padHjk48F^&z} zf`5+~{64Mb-VOxsJbL{m*5x5$ygZ$R;^U4u*otG$IuW{d4im5<3qi8Ud2qiql% zwDb>Y=>iY;c$geWuOB8!upi!tA4!LnML;NGk9J6*SbABPA3ka~R~OxVF6%zyKcPk6 zBJfjM*%%I_HHzat!V5^I$%;35%OjzB3_1` zxPDpc#}7k4yMzVbt=u-b_aCDr3_vq1!_i&6X1KbO{R|I2tc(EUnq{M=TY44W-Z9LX z_th}3s@G`-<~Vv8ZT55Zs`?t8dx1a9hc` z&wA>Nbzx5&Q4sE=n1W)8vg$$RGVSeWv^3Jl>@W>f4_q`7R2ev810_YUk8$-hoy?!U z$dxud9$=!hJ`XyAp8?9x5}+$m&O$Ejb$GatM9HPhQ_c$+<+!BHhW$a3OHw5OC*&wi zK8${cWfMv>G=ppqw)8*87_ELyo|w9g%;kAndO(~V>7l~ZJ^cy;W3)VBb1hCi$Fz`i z#zs?m^EV*R%lb39XMsw%kFlmODf`DgDE$&1DuWE0)ePoQ&7i1DIdvJ-I;c@2WVeW* zNYp9_&iA%+>dK^wf_F*O#1fJbV?OTW8bZ}WVS7|;?9hFqSWr=NwB9)3fEqm9?;y7D zXXIK&=TBA}Di@wlBKmo?x~NdFi{%pw>QEJusl00Rk0c zvf7K=LC-(PO3y^D4xdv1t2~?gpp>>^Rk~!S@AiUyb)!vFF2~V{Gt0F&`fv~|meVRG2p@kyB8)(^{T8l_wRZ3ekmJ z$=n`!I}k;Ks<;SMH}GavnxoEucfkaY0I1xh_{bm7hl$)FyPs3T=!G{F6Y(1awh53M zkmc-_{E+jQ!>;dBXCc431p`#J_Yi}BK})C-)N}(evkcKu+^j;BoW`41p#+KGBs)%) zh)T6{pOZaiYNoEdNVVGrm2N5?$&&ic{xy(pHW>8z9imbhlk!w5=_+jw2E9&O)y|y! zZFca=FbVms2==gtoF+Ra$tF`yb@aLL_(dAHMBo(ymkC@Ua1}t-7j!!>%rb4gPE&qO zfP9Y97j@ literal 0 HcmV?d00001 diff --git a/ControllByPs4/commands/backend/backend.py b/ControllByPs4/commands/backend/backend.py new file mode 100644 index 0000000..32916a7 --- /dev/null +++ b/ControllByPs4/commands/backend/backend.py @@ -0,0 +1,178 @@ +# Assuming you have not changed the general structure of the template no modification is needed in this file. +# from . import commands +from ast import arg +from glob import glob +from ...lib import fusion360utils as futil +import threading +import adsk.core +import adsk.fusion +import adsk.cam +import traceback +import json + +CMD_NAME = 'View Controller backend' + +app = adsk.core.Application.get() +ui = app.userInterface +stopFlag = None +cameraViewEvent = 'CameraViewEventId' +updateConstantsEvent = "UpdateConstantsEventId" + +customEvents = [] +local_handlers = [] + +X_ROTATION = 0 +Y_ROTATION = 0 +Z_ROTATION = 0 +X_PAN = 0 +Y_PAN = 0 +Z_PAN = 0 + + +class UpdateConstantsEventHandler(adsk.core.CustomEventHandler): + def __init__(self): + super().__init__() + + def notify(self, args: adsk.core.CustomEventArgs) -> None: + futil.log(f'{CMD_NAME} UpdateConstants notity...') + eventArgs = json.loads(args.additionalInfo) + global X_ROTATION, Y_ROTATION, Z_ROTATION + global X_PAN, Y_PAN, Z_PAN + X_ROTATION = float(eventArgs["X_rotation"]) + Y_ROTATION = float(eventArgs["Y_rotation"]) + Z_ROTATION = float(eventArgs["Z_rotation"]) + X_PAN = float(eventArgs["X_pan"]) + Y_PAN = float(eventArgs["Y_pan"]) + Z_PAN = float(eventArgs["Z_pan"]) + + +# The event handler that responds to the custom event being fired. +class CameraViewEventHandler(adsk.core.CustomEventHandler): + def __init__(self): + super().__init__() + self.viewport = app.activeViewport + + def notify(self, args: adsk.core.CustomEventArgs): + global app + try: + # Make sure a command isn't running before changes are made. + activeCmd = ui.activeCommand + if activeCmd != 'SelectCommand': + ui.commandDefinitions.itemById('SelectCommand').execute() + + camera = self.viewport.camera + eye = camera.eye + target = camera.target + up = camera.upVector + zoom = camera.viewExtents + + front = eye.vectorTo(target) + right = up.crossProduct(front) + rotate_matrix = adsk.core.Matrix3D.create() + rotate_matrix.setWithCoordinateSystem(target, right, front, up) + mat = rotate_matrix.asArray() + + # Get the value from the JSON data passed through the event. + eventArgs: dict = json.loads(args.additionalInfo) + + X_radians = float(eventArgs.get('X_rotation', 0)) * X_ROTATION + if X_radians: + rotate_matrix.setToRotation(X_radians, front, target) + eye.transformBy(rotate_matrix) + up.transformBy(rotate_matrix) + + Y_radians = float(eventArgs.get('Y_rotation', 0)) * Y_ROTATION + if Y_radians: + rotate_matrix.setToRotation(Y_radians, right, target) + eye.transformBy(rotate_matrix) + up.transformBy(rotate_matrix) + + Z_radians = float(eventArgs.get('Z_rotation', 0)) * Z_ROTATION + if Z_radians: + rotate_matrix.setToRotation(Z_radians, up, target) + eye.transformBy(rotate_matrix) + up.transformBy(rotate_matrix) + + X_pan = float(eventArgs.get('X_pan', 0)) * X_pan + Y_pan = float(eventArgs.get('Y_pan', 0)) * Y_pan + Z_pan = float(eventArgs.get('Z_pan', 0)) * Z_pan + if any([X_pan, Z_pan]): + move_vector = adsk.core.Vector3D.create(X_pan, 0, Z_pan) + move_vector.transformBy(rotate_matrix) + eye.translateBy(move_vector) + target.translateBy(move_vector) + + if Y_pan: + zoom = zoom + Y_pan * 10 + + camera.isSmoothTransition = True + camera.eye = eye + camera.upVector = up + camera.target = target + camera.viewExtents = zoom + app.activeViewport.camera = camera + app.activeViewport.refresh() + + except: + if ui: + ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) + + def rotate(self, X_radians: float, Y_radians: float, Z_radians: float): + pass + + +# The class for the new thread. +class ControllerThread(threading.Thread): + def __init__(self, event): + threading.Thread.__init__(self) + self.stopped = event + + def run(self): + # Every five seconds fire a custom event, passing a random number. + while not self.stopped.wait(2): + futil.log(f'{CMD_NAME} Thread start sending data') + args = {'X_rotation': 0.0, 'Y_rotation': 0.0, 'Z_rotation': 0.0, + 'X_pan': 0.0, 'Y_pan': 0.0, 'Z_pan': 0.0} + app.fireCustomEvent(cameraViewEvent, json.dumps(args)) + + +def start(): + + futil.log(f'{CMD_NAME} Start...') + # Register the custom event and connect the handler. + global customEvents + customEvents.append(app.registerCustomEvent(cameraViewEvent)) + onCameraViewEvent = CameraViewEventHandler() + customEvents[0].add(onCameraViewEvent) + local_handlers.append(onCameraViewEvent) + futil.log(f'{CMD_NAME} CameraViewEvent register') + + customEvents.append(app.registerCustomEvent(updateConstantsEvent)) + onUpadateConstantEvent = UpdateConstantsEventHandler() + customEvents[1].add(onUpadateConstantEvent) + local_handlers.append(onUpadateConstantEvent) + futil.log(f'{CMD_NAME} UpdateConstantsEvent register') + + # Create a new thread for the other processing. + global stopFlag + stopFlag = threading.Event() + myThread = ControllerThread(stopFlag) + # myThread.start() + futil.log(f'{CMD_NAME} ControllerThread started') + + +def stop(): + try: + for event, handler in zip(customEvents, local_handlers): + event.remove(handler) + # if local_handlers.count: + # customEvent.remove(local_handlers[0]) + + stopFlag.set() + app.unregisterCustomEvent(cameraViewEvent) + app.unregisterCustomEvent(updateConstantsEvent) + ui.messageBox('Stop addin') + except: + futil.handle_error('stop') + # if ui: + # ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) diff --git a/ControllByPs4/commands/commandDialog/__init__.py b/ControllByPs4/commands/commandDialog/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ControllByPs4/commands/commandDialog/__pycache__/__init__.cpython-39.pyc b/ControllByPs4/commands/commandDialog/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8eaa6a146579f03b80ce2ebb17f8a34ac28c3810 GIT binary patch literal 170 zcmYe~<>g`kf?@`hWDxxrL?8o3AjbiSi&=m~3PUi1CZpdsA zRn*PboO7_JLLMjoAb+J#smjTJActJ!_Zr|LIYSm6-urst>wYW!Lc!7C(+wWB{`)}F z{)58&Ckw)t@Wd6OX;h=6qj^NVbx)@{H9AJu^emzQZ+0@>td|8I=h>dkNPD5}jB;bm z%d>pD;1yZ6UHV?57QD;w&b%g11Z^Z-wT(RhswKnBKlMx~=FPMenkE zV=^YRK#OC;d+kK?@6!@3f2Vm5=pwDa+f~2#I$ipK&}F*vo$0-ykT(^wO4k5+YYw?Z zZv*nSLf%nx?$En{ysMC3DC8b}4Up>Gs{8Z-An#Ffs8!t`@wRq&y4lB>zg!>AL`&G0PXQP^dnkZTG#Z1JEcV%Q=G<9$D59l4TX zJAUY&FrIEJ7dVTfK5wyDYArm+S-~mWD=inQCxz`tIZEiq!jothAD2 zHrR0x1_JIcmPULq;er+jUkGc`)Q#EB4yrfClv0RvHBCVdXV>aFXrN-X|tNd@f{>9Us0jzDa zmWUtq2I4ddA5DGm(Zs(t2K(_ZpQa~`CrsjsPr-Be;KSZPTCwoCcnfV_2BPU1VqckN z(aalpqipbZ0sEPo7yv3a*#>6fCSZCEoWlf{u~L`F0G~ydfH`)`8$+G15B1T)SR>ld z;C~z%39lT4>{cC~hh6y^l3Pe_Be{d*E|PmlN=OPoq)l0e3AV$kCVvCbHxZp#II+#t z-|&)Chf~*?kauv68H=d*Tj0{0$P@K7Ok%^sAHv8>B2Ay4#4SjS(+{T0Y2f@D1fh+H z&>_{47y6jMDYdrIHZO^=+L<MsY6-R^mM569($en5>NHQKLFI0qVLBq8N$0%DBjICAUpPPo;I}^V$vEU*wH+8kzn2o!}Q#VT7GAe3*zbuUjiFR z12Qs4mxtI(QjsjA%vRXzix@0T<8P(eia3+bH-4wj)Bt1?l{Gd7hk^&;iM$O_Ukgt< zOwCE-KbdOyy`C)iEfJhCh*;Wh37PLhzKheWEGyuTe!nBOS$HB&zs4b0KdNY(mlF@+gs8dE=j@T!;s zKev*23N*++C>dkY&I~nbt|u~NBPC~288VWR?No+XQnHiE5I;)Jr!o{cB^TFK0i-3d zFmi?(v?WjkRXmjE<6$!~R2mQYt`A;v-c;AmAHhka^JMDp{38V%&47;;;LU)~5U`%0 zXYTwd_7HQ)XP>h(Y^s#XRqK`KeW}k5aKm|LA=67X z`#We5qduTN;eUnqHEq!~EqIi+SU4bUYR~~ew*-YwA3?u_sUJEb>wE15IAiK0`tHU1 zu1X7T9U7ApMiZ@Fym;y!Lo?v|Zc7chB66!4X(e8Rw|?VfQV(cq6i8dicBw_w?CWNc zD`{p+rZm$9|A2jC^;dvoNCs+L@rwI^T|4eI<6ss3f5y3lzXz(lyI64{a|P&)=~)xY zm^buSp2VNx!EUI!I#CsTQ|*)J{7=+1HHyxk-P986@zjN|Yq+T;{BbZQI?ierbdi`f zQ}_9ql9*cg`$(=U$+rOe7d#V<424u5$_1<$A7aVi>o6|$D27TCJmcs!$sOd7LtXh1 zlHUQ5xmvH+30kUVO5=oyBqj^}nDMPpFn$cJsp^Yl9{NgXJ&%%J*r_!dTf2%+dLpc7 zd=Ux!vrBs?)i&M7-!Xf>IF)8Q3PPEs0T2BylUe^6w7!7b&E|2?Va+D5;97Nh?Eh5j zBiGW(mezY^*BbOfDtXItIy!?f6{zTuE6VFrr=LwgSCeZKcTsba%%yfk6RTUDyL)8? z)vMX-U8trV_IosZjCs+93WNO`(u}!GOkx^l1}MDq#JSS3{#d4Iui2H#dlk20S8|oo EPqX3rX8-^I literal 0 HcmV?d00001 diff --git a/ControllByPs4/commands/commandDialog/entry.py b/ControllByPs4/commands/commandDialog/entry.py new file mode 100644 index 0000000..aed17f8 --- /dev/null +++ b/ControllByPs4/commands/commandDialog/entry.py @@ -0,0 +1,190 @@ +import adsk.core +import os +from ...lib import fusion360utils as futil +from ... import config +import json +app = adsk.core.Application.get() +ui = app.userInterface + + +# TODO *** Specify the command identity information. *** +CMD_ID = f'{config.COMPANY_NAME}_{config.ADDIN_NAME}_cmdDialog' +CMD_NAME = 'View Controller' +CMD_Description = 'A Fusion 360 Add-in Command with a dialog' + +# Specify that the command will be promoted to the panel. +IS_PROMOTED = True + +# TODO *** Define the location where the command button will be created. *** +# This is done by specifying the workspace, the tab, and the panel, and the +# command it will be inserted beside. Not providing the command to position it +# will insert it at the end. +WORKSPACE_ID = 'FusionSolidEnvironment' +PANEL_ID = 'SolidScriptsAddinsPanel' +COMMAND_BESIDE_ID = 'ScriptsManagerCommand' + +# Resource location for command icons, here we assume a sub folder in this directory named "resources". +ICON_FOLDER = os.path.join(os.path.dirname( + os.path.abspath(__file__)), 'resources', '') + +# Local list of event handlers used to maintain a reference so +# they are not released and garbage collected. +local_handlers = [] + + +# Executed when add-in is run. +def start(): + # Create a command Definition. + cmd_def = ui.commandDefinitions.addButtonDefinition( + CMD_ID, CMD_NAME, CMD_Description, ICON_FOLDER) + + # Define an event handler for the command created event. It will be called when the button is clicked. + futil.add_handler(cmd_def.commandCreated, command_created) + + # ******** Add a button into the UI so the user can run the command. ******** + # Get the target workspace the button will be created in. + workspace = ui.workspaces.itemById(WORKSPACE_ID) + + # Get the panel the button will be created in. + panel = workspace.toolbarPanels.itemById(PANEL_ID) + + # Create the button command control in the UI after the specified existing command. + control = panel.controls.addCommand(cmd_def, COMMAND_BESIDE_ID, False) + + # Specify if the command is promoted to the main toolbar. + control.isPromoted = IS_PROMOTED + + +# Executed when add-in is stopped. +def stop(): + # Get the various UI elements for this command + workspace = ui.workspaces.itemById(WORKSPACE_ID) + panel = workspace.toolbarPanels.itemById(PANEL_ID) + command_control = panel.controls.itemById(CMD_ID) + command_definition = ui.commandDefinitions.itemById(CMD_ID) + + # Delete the button command control + if command_control: + command_control.deleteMe() + + # Delete the command definition + if command_definition: + command_definition.deleteMe() + + +# Function that is called when a user clicks the corresponding button in the UI. +# This defines the contents of the command dialog and connects to the command related events. +def command_created(args: adsk.core.CommandCreatedEventArgs): + # General logging for debug. + futil.log(f'{CMD_NAME} Command Created Event') + + # https://help.autodesk.com/view/fusion360/ENU/?contextId=CommandInputs + inputs = args.command.commandInputs + + # TODO Define the dialog for your command by adding different inputs to the command. + + # # Create a simple text box input. + # inputs.addTextBoxCommandInput( + # 'text_box', 'Some Text', 'Enter some text.', 1, False) + + default_angle = adsk.core.ValueInput.createByString('5') + inputs.addAngleValueCommandInput("x_rotation", "X Rotation", default_angle) + inputs.addAngleValueCommandInput("y_rotation", "Y Rotation", default_angle) + inputs.addAngleValueCommandInput("z_rotation", "Z Rotation", default_angle) + + # # Create a value input field and set the default using 1 unit of the default length unit. + defaultLengthUnits = app.activeProduct.unitsManager.defaultLengthUnits + default_value_x = adsk.core.ValueInput.createByString("1") + default_value_y = adsk.core.ValueInput.createByString("2") + default_value_z = adsk.core.ValueInput.createByString("3") + inputs.addValueInput('x_pan', 'X Disytance', + defaultLengthUnits, default_value_x) + inputs.addValueInput('y_pan', 'Y Disytance', + defaultLengthUnits, default_value_y) + inputs.addValueInput('z_pan', 'Z Disytance', + defaultLengthUnits, default_value_z) + + # TODO Connect to the events that are needed by this command. + futil.add_handler(args.command.execute, command_execute, + local_handlers=local_handlers) + # futil.add_handler(args.command.inputChanged, command_input_changed, local_handlers=local_handlers) + # futil.add_handler(args.command.executePreview, command_preview, local_handlers=local_handlers) + # futil.add_handler(args.command.validateInputs, command_validate_input, local_handlers=local_handlers) + futil.add_handler(args.command.destroy, command_destroy, + local_handlers=local_handlers) + + +# This event handler is called when the user clicks the OK button in the command dialog or +# is immediately called after the created event not command inputs were created for the dialog. +def command_execute(args: adsk.core.CommandEventArgs): + # General logging for debug. + futil.log(f'{CMD_NAME} Command Execute Event') + + # TODO ******************************** Your code here ******************************** + + # Get a reference to your command's inputs. + inputs = args.command.commandInputs + # text_box: adsk.core.TextBoxCommandInput = inputs.itemById('text_box') + # value_input: adsk.core.ValueCommandInput = inputs.itemById('value_input') + triad_input: adsk.core.TriadCommandInput = inputs.itemById('matrix_input') + args = {} + # value_input: adsk.core.ValueCommandInput = inputs.itemById["x_rotation"] + args["X_rotation"] = inputs.itemById("x_rotation").value + args["Y_rotation"] = inputs.itemById("y_rotation").value + args["Z_rotation"] = inputs.itemById("z_rotation").value + + # angle_input: adsk.core.AngleValueCommandInput = inputs.itemById["x_pan"] + args["X_pan"] = inputs.itemById("x_pan").value + args["Y_pan"] = inputs.itemById("y_pan").value + args["Z_pan"] = inputs.itemById("z_pan").value + # Do something interesting + # text = text_box.text + # expression = value_input.expression + # msg = f'Your text: {text}
Your value: {expression}' + # ui.messageBox(msg) + + app.fireCustomEvent('UpdateConstantsEventId', json.dumps(args)) + +# This event handler is called when the command needs to compute a new preview in the graphics window. + + +def command_preview(args: adsk.core.CommandEventArgs): + # General logging for debug. + futil.log(f'{CMD_NAME} Command Preview Event') + inputs = args.command.commandInputs + + +# This event handler is called when the user changes anything in the command dialog +# allowing you to modify values of other inputs based on that change. +def command_input_changed(args: adsk.core.InputChangedEventArgs): + changed_input = args.input + inputs = args.inputs + + # General logging for debug. + futil.log( + f'{CMD_NAME} Input Changed Event fired from a change to {changed_input.id}') + + +# This event handler is called when the user interacts with any of the inputs in the dialog +# which allows you to verify that all of the inputs are valid and enables the OK button. +def command_validate_input(args: adsk.core.ValidateInputsEventArgs): + # General logging for debug. + futil.log(f'{CMD_NAME} Validate Input Event') + + inputs = args.inputs + + # Verify the validity of the input values. This controls if the OK button is enabled or not. + # valueInput = inputs.itemById('value_input') + # if valueInput.value >= 0: + # args.areInputsValid = True + # else: + # args.areInputsValid = False + + +# This event handler is called when the command terminates. +def command_destroy(args: adsk.core.CommandEventArgs): + # General logging for debug. + futil.log(f'{CMD_NAME} Command Destroy Event') + + global local_handlers + local_handlers = [] diff --git a/ControllByPs4/commands/commandDialog/resources/16x16.png b/ControllByPs4/commands/commandDialog/resources/16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..03babdc056577fea50543b03d15c480d88c89f4c GIT binary patch literal 415 zcmV;Q0bu@#P)KA9k4D0+<1qc$SunL_18+0mJ|no~1oAf13dfUQ*u%01+5>;@Y z)*+9ui?QG#{8m7wjtRZ_7;GpXT!7Xr);$MsL(ih)&$~U6?q5HKp5f86w1-XuNy<+m ziM)=y6Z(%>u-E%a+b3{!z~(0Dcce}w4hGl2o zy!Y*!_hU9;+cvg|2T^S6rX^)vFJ%&8b=}+Q=c_!Rn^p=y6@XDMWu{S-Z=yr$0lx7w zfD`uQ?@^2g>JWm^v+>X~-24*Dhu;%x1PJ3R3<2zK=m1JqAmKlP zDq$QUjH_f1xeXV70tRP!SLksYasu2n+8vPyj)4_;EL;NEjmh{7Ku(s5R3S27}iUf9JR=g?(3!*!+J;9 zUT_wma2h1zM_2-vG0C{tdN&M9fIR<@GLZ?KsX8NH3l#%YA*w1m9+ieEZyG*X{=mcA zg}c6U`{&Ev_0^}zWO8K~#>XH6%#Gg_#E1M#R{@vf?{50-efxleXHSKVola*wo6X)d z8jW}Cohn3AUOuU6$P8U52s$Vhi^5#D+huOKD3{A%Bm@GUJ3(B1fPzC}jX=PKBo-VW zYmdg`k<&K@gTY(B2UHi5Sa5Xo;xPa=P^;C17+}rfd7M|WX0wUWXe0>a^LgjFMu4T3 zZdzI#m(ql7{{(Pf(=;p=3qdfQPNU!Ni&-Ec;l0VQVd$nMB~UMA+;&^(-TY>OoXuuc zo|31bhs6KCB90w|u j%CBTHsr;pz&*%6H8=VB7i~>0q00000NkvXXu0mjfNzF8J literal 0 HcmV?d00001 diff --git a/ControllByPs4/commands/commandDialog/resources/64x64.png b/ControllByPs4/commands/commandDialog/resources/64x64.png new file mode 100644 index 0000000000000000000000000000000000000000..dd285fd1c9a47ff154e426da5c90fcdd96239c2c GIT binary patch literal 1077 zcmV-51j_q~P)ZWvYv= zx{iE7uCu6eC_iv#i2_oDd_h3U2V4qV&?G1gA|e+p8iVi7XYZ_c_iU3VU16PXXWqN@ z?9A+XW-u7wA!GJIvj_0lmLWfkSW_)^9A4)TT$bSUz1i%S7VI6)LtqJ=8o~!!779c@B##BTgKfaKCsQSSY zAccGkt0L(1Lpl@8Fq*{WXiOky8UVIrog(z;+3p6e^Q)*IlOQF4q|v1DB@vW}_)E#( zW#It8o*>2aBUgl60hr{=hFlRc1)%ABk_a@l6JcTy^uuVr2ILV3#z|jJ6o3Lx!p^A!-OI|=a6RemBQsf0#sW1)tPT4Ix zkR~snQVxss^n(T}KLGR-*Gp8@6~)9QFAXXJ>=krSq_yp|#KaFHA;LB-TdMiT9*rRd zR$H8sqo0b7oe9Te3KX&(b;MNus$f&v&$~x}+qY-nP2f7Lz?1|%4t?D)7bTX)8G~s7-qHr9GAI)?)||C*KA=q`RM9orn&+0o z9fdtUs1`&8>>W@cl?$!_VyEbvf<6Td zj*eLOZ)|J~U1tg)c3J%}LYYN4K0apMKPrHU6Cxtzd_}*})fg4&^9vK_6Qq_w#!N^a zNfV!r=98iw?{L_M_4Re;u)~n91tdgBJ&#A%+kP0a1PEM5s+~4ErMXZ!A(A!?rO)P; z4eVklA;M+V$qOjGF+z{SDdh=`X_7a(3}!))77YxQeSe)Wz6@qz+T?Y>+KZE>U~L&J vE37Vqb%eDUVC!9AE-Lr>yytoP90u?YjV+lgrL2(V00000NkvXXu0mjf+LYiK literal 0 HcmV?d00001 diff --git a/ControllByPs4/config.py b/ControllByPs4/config.py new file mode 100644 index 0000000..d4eb231 --- /dev/null +++ b/ControllByPs4/config.py @@ -0,0 +1,21 @@ +# Application Global Variables +# This module serves as a way to share variables across different +# modules (global variables). + +import os + +# Flag that indicates to run in Debug mode or not. When running in Debug mode +# more information is written to the Text Command window. Generally, it's useful +# to set this to True while developing an add-in and set it to False when you +# are ready to distribute it. +DEBUG = True + +# Gets the name of the add-in from the name of the folder the py file is in. +# This is used when defining unique internal names for various UI elements +# that need a unique name. It's also recommended to use a company name as +# part of the ID to better ensure the ID is unique. +ADDIN_NAME = os.path.basename(os.path.dirname(__file__)) +COMPANY_NAME = 'BTL' + +# Palettes +sample_palette_id = f'{COMPANY_NAME}_{ADDIN_NAME}_palette_id' diff --git a/ControllByPs4/lib/fusion360utils/__init__.py b/ControllByPs4/lib/fusion360utils/__init__.py new file mode 100644 index 0000000..56e95d5 --- /dev/null +++ b/ControllByPs4/lib/fusion360utils/__init__.py @@ -0,0 +1,2 @@ +from .general_utils import * +from .event_utils import * diff --git a/ControllByPs4/lib/fusion360utils/__pycache__/__init__.cpython-39.pyc b/ControllByPs4/lib/fusion360utils/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bf5cd12010744e06648b151194972371a3e87922 GIT binary patch literal 219 zcmYe~<>g`kf?@`hWGf*37{oyaOhAqU5EqL8i4=wu#vFza2+atjnSvQKnO`yjr8F6D zF>3i~GDY#Gr{<*=CFaDJmSpA>M{%c?rRJ4DI4c>7n1M>c#4m4Ws~F$PfTH}Y)Z~(4 z{esGpjQl+Pw9?|t{5)eb1AXWGypp2)oE)dhfMS!FoXn&cxE$EznE3e2yv&mLc)fzk WTO2mI`6;D2sdgZz6ocH%!3Y4_p*TqZ literal 0 HcmV?d00001 diff --git a/ControllByPs4/lib/fusion360utils/__pycache__/event_utils.cpython-39.pyc b/ControllByPs4/lib/fusion360utils/__pycache__/event_utils.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d442d6e18b99779f0f860ab314f6e7dbf61a7d51 GIT binary patch literal 2894 zcmai0U2hvj6rEYG*N)>P{i4uHzyKBPqSmbhLa3?=B|?A@X+`HRK%h+Eu zS$qOazCp8ppp#7UjP>c?%lOFad%Ti0`o3&PKWmPHe!$rli(8W8*L?0Nf2X~(q&(G8 z%QATG%a&{(2K}yFlAS}=Uy*0AR=q=SEaQ!?Tsds^SLHd?k*m+ST$5)oUz7YH3(vm> z4z>~Uvb`Q>Sv<(pYYxdPUUs)*Ei)AyC?5;}EVX9=c-0O4%o_l6% zJOW;O+fA#TH*SbW*ilXL!H!A_G0DebFV+RAOLDDA7B8I9bNg$f#Z1L;tdk zE%0KdVzTKJRVOSJZ?#VRI21ZBPEmFoR77(faYUt*a1o%!Vk^rBaV8uaNFkBLr&$S> z6M#3^Ikx0V=I$dNFG0crnak7nU7-1v$cH3?nRg8_EV-O$v+}@K(7NMX`pbW6DkE zudP$WSr=-Hk-Ct#6{&P7EY-(aXW2sc4z!l5Cu8+1I?mO6-@J!$=vUl17Uu*eO)S+9 zNm0lvq}MPg7-~L8&2Jpw7MS{yjk&oz^|e><7v8k#Zh+=PTu>Wf11^(lm}*tSG(=As z#Jd!>VPMW<`hOUlyWX(IoW;vuqgevQTC4mbce0Q>?p&6h%pf>nMsU;wS>l`{?eYRc`0|;oCsnln2mKZKt70Dq;AE6u+07IKy{(zs|1 zknHJj@(TnmDH!*7mj`_R>RUlqJHvp8p}Q3vtk7}YDEe(2XEPCzVLl=G%8aW-Wm(PF z$F%w(bq-By=A{itESb>e-G;e}0pg7!3fXfUzC?~&thjf&oC7Xn;U}~zXnDuG*fAsv zy$vMrMtH_7V^#(zQn+9Yg+RF!OZ%jkFohvzp612)B-@VlQ&VAuE zY+*{DZV^{;T#CB{aR)AB(=p}kJ5{l~i*I3OucL#N9-8mBJnsGDgMQDWQTLqS literal 0 HcmV?d00001 diff --git a/ControllByPs4/lib/fusion360utils/__pycache__/general_utils.cpython-39.pyc b/ControllByPs4/lib/fusion360utils/__pycache__/general_utils.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..68155231fdddd097b30a196ae9ec7c99956ea8ae GIT binary patch literal 1672 zcmZvcQEwYX5P)~@&W?SyQ@2Gy2nnqaFP5lN1nNTth$J*9s6-L8LYyL5=i9x@IqO?% zcTM8RJe4Q@LW|Tq_K)x*_LZmd6L?}~&!$O~J>7U`cV;}h^UbBbUQA#Z@=5krn~=Xz zxjLGld;_of0|Y0WN|MySG@)J(l2C+`XwrDyyd=qn*qF4E_Qe(tcqrp(C+SckI+JeF z{h3sKO7P)P(*1>0!9(Ibdy`Eb<$<_UYogB^uR`AB8^1S_ySxMIecpN%@HUTO)Y&St|nW-xYiF`tUcn#W#U zosB(sz@D85wpJk^gcy1gf9kctI_JOdPDR*Sors7 z@A2^uizBTjBC}?Dwy-Cv+Ro<&3h?=(huaX)Y9;0F;>dh)EX(on|9f+&mpLv(C3GrB zUK`F9`VNHs5MHwhg0x%VCXMN4*aGSI-UKeH(y2)L=0u&1R<#+8)p-`6$7W8H$Mhx2AQ)RAByr>GBynSjP}Kyi4R zIj;Fw7k9tH!92~(&mD~q2W?M+Zb4Z!d`^kRudD8WaBZv8OpMd))Wy(x)6|Z{dFFz7 z>EabDyXsuOhYm<^E$*XhxBg6w{FQ$OD+d37#C`fv7*UN-4(R^iz6+Gm?}O&r*nLB6 zzIVB}&dv<#4@H3%aA6^=Mv`3*YO4<_D|8MC>JM;@X#7smF3Og6{Ke>_TI; vi^fXH`n;IIm85<8KJ(U>Q^n^}eBA{Lvjw6>;R(9583wcqt<$7&`0>_%uI|1Q literal 0 HcmV?d00001 diff --git a/ControllByPs4/lib/fusion360utils/event_utils.py b/ControllByPs4/lib/fusion360utils/event_utils.py new file mode 100644 index 0000000..97a09b0 --- /dev/null +++ b/ControllByPs4/lib/fusion360utils/event_utils.py @@ -0,0 +1,88 @@ +# Copyright 2022 by Autodesk, Inc. +# Permission to use, copy, modify, and distribute this software in object code form +# for any purpose and without fee is hereby granted, provided that the above copyright +# notice appears in all copies and that both that copyright notice and the limited +# warranty and restricted rights notice below appear in all supporting documentation. +# +# AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. AUTODESK SPECIFICALLY +# DISCLAIMS ANY IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. +# AUTODESK, INC. DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +# UNINTERRUPTED OR ERROR FREE. + +import sys +from typing import Callable + +import adsk.core +from .general_utils import handle_error + + +# Global Variable to hold Event Handlers +_handlers = [] + + +def add_handler( + event: adsk.core.Event, + callback: Callable, + *, + name: str = None, + local_handlers: list = None +): + """Adds an event handler to the specified event. + + Arguments: + event -- The event object you want to connect a handler to. + callback -- The function that will handle the event. + name -- A name to use in logging errors associated with this event. + Otherwise the name of the event object is used. This argument + must be specified by its keyword. + local_handlers -- A list of handlers you manage that is used to maintain + a reference to the handlers so they aren't released. + This argument must be specified by its keyword. If not + specified the handler is added to a global list and can + be cleared using the clear_handlers function. You may want + to maintain your own handler list so it can be managed + independently for each command. + + :returns: + The event handler that was created. You don't often need this reference, but it can be useful in some cases. + """ + module = sys.modules[event.__module__] + handler_type = module.__dict__[event.add.__annotations__['handler']] + handler = _create_handler(handler_type, callback, event, name, local_handlers) + event.add(handler) + return handler + + +def clear_handlers(): + """Clears the global list of handlers. + """ + global _handlers + _handlers = [] + + +def _create_handler( + handler_type, + callback: Callable, + event: adsk.core.Event, + name: str = None, + local_handlers: list = None +): + handler = _define_handler(handler_type, callback, name)() + (local_handlers if local_handlers is not None else _handlers).append(handler) + return handler + + +def _define_handler(handler_type, callback, name: str = None): + name = name or handler_type.__name__ + + class Handler(handler_type): + def __init__(self): + super().__init__() + + def notify(self, args): + try: + callback(args) + except: + handle_error(name) + + return Handler diff --git a/ControllByPs4/lib/fusion360utils/general_utils.py b/ControllByPs4/lib/fusion360utils/general_utils.py new file mode 100644 index 0000000..fcf2667 --- /dev/null +++ b/ControllByPs4/lib/fusion360utils/general_utils.py @@ -0,0 +1,64 @@ +# Copyright 2022 by Autodesk, Inc. +# Permission to use, copy, modify, and distribute this software in object code form +# for any purpose and without fee is hereby granted, provided that the above copyright +# notice appears in all copies and that both that copyright notice and the limited +# warranty and restricted rights notice below appear in all supporting documentation. +# +# AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. AUTODESK SPECIFICALLY +# DISCLAIMS ANY IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. +# AUTODESK, INC. DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +# UNINTERRUPTED OR ERROR FREE. + +import os +import traceback +import adsk.core + +app = adsk.core.Application.get() +ui = app.userInterface + +# Attempt to read DEBUG flag from parent config. +try: + from ... import config + DEBUG = config.DEBUG +except: + DEBUG = False + + +def log(message: str, level: adsk.core.LogLevels = adsk.core.LogLevels.InfoLogLevel, force_console: bool = False): + """Utility function to easily handle logging in your app. + + Arguments: + message -- The message to log. + level -- The logging severity level. + force_console -- Forces the message to be written to the Text Command window. + """ + # Always print to console, only seen through IDE. + print(message) + + # Log all errors to Fusion log file. + if level == adsk.core.LogLevels.ErrorLogLevel: + log_type = adsk.core.LogTypes.FileLogType + app.log(message, level, log_type) + + # If config.DEBUG is True write all log messages to the console. + if DEBUG or force_console: + log_type = adsk.core.LogTypes.ConsoleLogType + app.log(message, level, log_type) + + +def handle_error(name: str, show_message_box: bool = False): + """Utility function to simplify error handling. + + Arguments: + name -- A name used to label the error. + show_message_box -- Indicates if the error should be shown in the message box. + If False, it will only be shown in the Text Command window + and logged to the log file. + """ + + log('===== Error =====', adsk.core.LogLevels.ErrorLogLevel) + log(f'{name}\n{traceback.format_exc()}', adsk.core.LogLevels.ErrorLogLevel) + + # If desired you could show an error as a message box. + if show_message_box: + ui.messageBox(f'{name}\n{traceback.format_exc()}') diff --git a/demo/.env b/demo/.env new file mode 100644 index 0000000..6aedf1e --- /dev/null +++ b/demo/.env @@ -0,0 +1 @@ +PYTHONPATH=C:/Users/bartool/AppData/Local/Autodesk/webdeploy/production/9209df45963e1599ff476303834125d21fd43de4/Api/Python/packages diff --git a/demo/.vscode/launch.json b/demo/.vscode/launch.json new file mode 100644 index 0000000..1c69300 --- /dev/null +++ b/demo/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + "version": "0.2.0", + "configurations": [{ + "name": "Python: Attach", + "type": "python", + "request": "attach", + "pathMappings": [{ + "localRoot": "${workspaceRoot}", + "remoteRoot": "${workspaceRoot}" + }], + "osx": { + "filePath": "${file}" + }, + "windows": { + "filePath": "${file}" + }, + "port": 9000, + "host": "localhost" + }] +} \ No newline at end of file diff --git a/demo/.vscode/settings.json b/demo/.vscode/settings.json new file mode 100644 index 0000000..5627768 --- /dev/null +++ b/demo/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "python.autoComplete.extraPaths": ["C:/Users/bartool/AppData/Roaming/Autodesk/Autodesk Fusion 360/API/Python/defs"], + "python.analysis.extraPaths": ["C:/Users/bartool/AppData/Roaming/Autodesk/Autodesk Fusion 360/API/Python/defs"], + "python.defaultInterpreterPath": "C:/Users/bartool/AppData/Local/Autodesk/webdeploy/production/9209df45963e1599ff476303834125d21fd43de4/Python/python.exe", + "python.pythonPath": "C:/Users/bartool/AppData/Local/Autodesk/webdeploy/production/9209df45963e1599ff476303834125d21fd43de4/Python/python.exe" +} \ No newline at end of file diff --git a/demo/demo.manifest b/demo/demo.manifest new file mode 100644 index 0000000..28ab33c --- /dev/null +++ b/demo/demo.manifest @@ -0,0 +1,10 @@ +{ + "autodeskProduct": "Fusion360", + "type": "script", + "author": "", + "description": { + "": "" + }, + "supportedOS": "windows|mac", + "editEnabled": true +} \ No newline at end of file diff --git a/demo/demo.py b/demo/demo.py new file mode 100644 index 0000000..4e2b6af --- /dev/null +++ b/demo/demo.py @@ -0,0 +1,58 @@ +# Fusion360API Python script +import adsk.core, adsk.fusion, adsk.cam, traceback +import math, random + +# Number of divisions during one revolution +COUNT = 60 + +def run(context): + ui = None + try: + app: adsk.core.Application = adsk.core.Application.get() + ui = app.userInterface + + # get state + vi :adsk.core.Viewport = app.activeViewport + camera :adsk.core.Camera = vi.camera #This is a deep copy. + eye :adsk.core.Point3D = camera.eye + tgt :adsk.core.Point3D = camera.target + up :adsk.core.Vector3D = camera.upVector + baseArea = camera.viewExtents + + # get matrix + front :adsk.core.Vector3D = eye.vectorTo(tgt) + right :adsk.core.Vector3D = up.copy() + right = right.crossProduct(front) + mat :adsk.core.Matrix3D = adsk.core.Matrix3D.create() + mat.setWithCoordinateSystem(tgt, right, front, up) + + # get position & ratio + unit = math.radians(360 // COUNT) + rads = [unit] * COUNT + ratios = [random.uniform(0.1, 5.0) for _ in range(COUNT)] + if 360 % COUNT != 0: + rads.append(math.radians(360 % COUNT)) + ratios.append(1) + + # show + camera.isSmoothTransition = False + for rad, ratio in zip(rads, ratios): + mat.setToRotation(rad, up, tgt) + eye.transformBy(mat) + up.transformBy(mat) + mat.setToRotation(rad, right, tgt) + eye.transformBy(mat) + up.transformBy(mat) + # mat.setToRotation(rad, front, tgt) + camera.eye = eye + camera.upVector = up + # zoom = baseArea * ratio + # camera.viewExtents = zoom + + vi.camera = camera + vi.refresh() + adsk.doEvents() + + except: + if ui: + ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) \ No newline at end of file diff --git a/eyeCameraTest/.env b/eyeCameraTest/.env new file mode 100644 index 0000000..6aedf1e --- /dev/null +++ b/eyeCameraTest/.env @@ -0,0 +1 @@ +PYTHONPATH=C:/Users/bartool/AppData/Local/Autodesk/webdeploy/production/9209df45963e1599ff476303834125d21fd43de4/Api/Python/packages diff --git a/eyeCameraTest/.vscode/launch.json b/eyeCameraTest/.vscode/launch.json new file mode 100644 index 0000000..1c69300 --- /dev/null +++ b/eyeCameraTest/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + "version": "0.2.0", + "configurations": [{ + "name": "Python: Attach", + "type": "python", + "request": "attach", + "pathMappings": [{ + "localRoot": "${workspaceRoot}", + "remoteRoot": "${workspaceRoot}" + }], + "osx": { + "filePath": "${file}" + }, + "windows": { + "filePath": "${file}" + }, + "port": 9000, + "host": "localhost" + }] +} \ No newline at end of file diff --git a/eyeCameraTest/.vscode/settings.json b/eyeCameraTest/.vscode/settings.json new file mode 100644 index 0000000..1c5eab8 --- /dev/null +++ b/eyeCameraTest/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "python.autoComplete.extraPaths": ["C:/Users/bartool/AppData/Roaming/Autodesk/Autodesk Fusion 360/API/Python/defs"], + "python.analysis.extraPaths": ["C:/Users/bartool/AppData/Roaming/Autodesk/Autodesk Fusion 360/API/Python/defs"], + "python.pythonPath": "C:/Users/bartool/AppData/Local/Autodesk/webdeploy/production/9209df45963e1599ff476303834125d21fd43de4/Python/python.exe" +} \ No newline at end of file diff --git a/eyeCameraTest/eyeCameraTest.manifest b/eyeCameraTest/eyeCameraTest.manifest new file mode 100644 index 0000000..28ab33c --- /dev/null +++ b/eyeCameraTest/eyeCameraTest.manifest @@ -0,0 +1,10 @@ +{ + "autodeskProduct": "Fusion360", + "type": "script", + "author": "", + "description": { + "": "" + }, + "supportedOS": "windows|mac", + "editEnabled": true +} \ No newline at end of file diff --git a/eyeCameraTest/eyeCameraTest.py b/eyeCameraTest/eyeCameraTest.py new file mode 100644 index 0000000..34df516 --- /dev/null +++ b/eyeCameraTest/eyeCameraTest.py @@ -0,0 +1,27 @@ +# Author- +# Description- + +import adsk.core +import adsk.fusion +import adsk.cam +import traceback + + +def run(context): + try: + + app = adsk.core.Application.get() + ui = app.userInterface + camera = app.activeViewport.camera + eye = camera.eye + target = camera.target + upvector = camera.upVector + baseExtent = camera.viewExtents + + ui.messageBox('Eye: {0}, {1}, {2} \ntarget: {3}, {4}, {5} \nupvector: {6}, {7}, {8}, \nviewExtants: {9}'.format( + eye.x, eye.y, eye.z, target.x, target.y, target.z, upvector.x, upvector.y, upvector.z, baseExtent)) + + except: + + if ui: + ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) diff --git a/rotate_Test/.env b/rotate_Test/.env new file mode 100644 index 0000000..6aedf1e --- /dev/null +++ b/rotate_Test/.env @@ -0,0 +1 @@ +PYTHONPATH=C:/Users/bartool/AppData/Local/Autodesk/webdeploy/production/9209df45963e1599ff476303834125d21fd43de4/Api/Python/packages diff --git a/rotate_Test/.vscode/launch.json b/rotate_Test/.vscode/launch.json new file mode 100644 index 0000000..1c69300 --- /dev/null +++ b/rotate_Test/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + "version": "0.2.0", + "configurations": [{ + "name": "Python: Attach", + "type": "python", + "request": "attach", + "pathMappings": [{ + "localRoot": "${workspaceRoot}", + "remoteRoot": "${workspaceRoot}" + }], + "osx": { + "filePath": "${file}" + }, + "windows": { + "filePath": "${file}" + }, + "port": 9000, + "host": "localhost" + }] +} \ No newline at end of file diff --git a/rotate_Test/.vscode/settings.json b/rotate_Test/.vscode/settings.json new file mode 100644 index 0000000..1c5eab8 --- /dev/null +++ b/rotate_Test/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "python.autoComplete.extraPaths": ["C:/Users/bartool/AppData/Roaming/Autodesk/Autodesk Fusion 360/API/Python/defs"], + "python.analysis.extraPaths": ["C:/Users/bartool/AppData/Roaming/Autodesk/Autodesk Fusion 360/API/Python/defs"], + "python.pythonPath": "C:/Users/bartool/AppData/Local/Autodesk/webdeploy/production/9209df45963e1599ff476303834125d21fd43de4/Python/python.exe" +} \ No newline at end of file diff --git a/rotate_Test/rotate_Test.manifest b/rotate_Test/rotate_Test.manifest new file mode 100644 index 0000000..28ab33c --- /dev/null +++ b/rotate_Test/rotate_Test.manifest @@ -0,0 +1,10 @@ +{ + "autodeskProduct": "Fusion360", + "type": "script", + "author": "", + "description": { + "": "" + }, + "supportedOS": "windows|mac", + "editEnabled": true +} \ No newline at end of file diff --git a/rotate_Test/rotate_Test.py b/rotate_Test/rotate_Test.py new file mode 100644 index 0000000..bde569a --- /dev/null +++ b/rotate_Test/rotate_Test.py @@ -0,0 +1,58 @@ +# Author- +# Description- + +import math +import adsk.core +import adsk.fusion +import adsk.cam +import traceback + + +def run(context): + ui = None + try: + print('hello, world') + app = adsk.core.Application.get() + + move_camera(app, app.activeViewport) + + ui = app.userInterface + # ui.messageBox('Hello script') + + except: + if ui: + ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) + + +def move_camera(app, view): + try: + camera = view.camera + + # target = adsk.core.Point3D.create(0, 0, 0) + up = adsk.core.Vector3D.create(0, 0, 1) + steps = 1000 + + eye = camera.eye + dist = camera.target.distanceTo(eye) + x_eye = eye.x + y_eye = eye.y + + for i in range(0, steps): + x = dist * math.cos((math.pi*2) * (i/steps)) + x_eye + y = dist * math.sin((math.pi*2) * (i/steps)) + y_eye + z = eye.z + + eye = adsk.core.Point3D.create(x, y, z) + + camera.eye = eye + # camera.target = target + # camera.upVector = up + + # camera.isSmoothTransition = False + view.camera = camera + adsk.doEvents() + view.refresh() + except: + ui = app.userInterface + if ui: + ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) diff --git a/tamplate/.env b/tamplate/.env new file mode 100644 index 0000000..6aedf1e --- /dev/null +++ b/tamplate/.env @@ -0,0 +1 @@ +PYTHONPATH=C:/Users/bartool/AppData/Local/Autodesk/webdeploy/production/9209df45963e1599ff476303834125d21fd43de4/Api/Python/packages diff --git a/tamplate/.vscode/launch.json b/tamplate/.vscode/launch.json new file mode 100644 index 0000000..1c69300 --- /dev/null +++ b/tamplate/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + "version": "0.2.0", + "configurations": [{ + "name": "Python: Attach", + "type": "python", + "request": "attach", + "pathMappings": [{ + "localRoot": "${workspaceRoot}", + "remoteRoot": "${workspaceRoot}" + }], + "osx": { + "filePath": "${file}" + }, + "windows": { + "filePath": "${file}" + }, + "port": 9000, + "host": "localhost" + }] +} \ No newline at end of file diff --git a/tamplate/.vscode/settings.json b/tamplate/.vscode/settings.json new file mode 100644 index 0000000..1c5eab8 --- /dev/null +++ b/tamplate/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "python.autoComplete.extraPaths": ["C:/Users/bartool/AppData/Roaming/Autodesk/Autodesk Fusion 360/API/Python/defs"], + "python.analysis.extraPaths": ["C:/Users/bartool/AppData/Roaming/Autodesk/Autodesk Fusion 360/API/Python/defs"], + "python.pythonPath": "C:/Users/bartool/AppData/Local/Autodesk/webdeploy/production/9209df45963e1599ff476303834125d21fd43de4/Python/python.exe" +} \ No newline at end of file diff --git a/tamplate/commands/__init__.py b/tamplate/commands/__init__.py new file mode 100644 index 0000000..0499301 --- /dev/null +++ b/tamplate/commands/__init__.py @@ -0,0 +1,30 @@ +# Here you define the commands that will be added to your add-in. + +# TODO Import the modules corresponding to the commands you created. +# If you want to add an additional command, duplicate one of the existing directories and import it here. +# You need to use aliases (import "entry" as "my_module") assuming you have the default module named "entry". +from .commandDialog import entry as commandDialog +from .paletteShow import entry as paletteShow +from .paletteSend import entry as paletteSend + +# TODO add your imported modules to this list. +# Fusion will automatically call the start() and stop() functions. +commands = [ + commandDialog, + paletteShow, + paletteSend +] + + +# Assumes you defined a "start" function in each of your modules. +# The start function will be run when the add-in is started. +def start(): + for command in commands: + command.start() + + +# Assumes you defined a "stop" function in each of your modules. +# The stop function will be run when the add-in is stopped. +def stop(): + for command in commands: + command.stop() \ No newline at end of file diff --git a/tamplate/commands/commandDialog/__init__.py b/tamplate/commands/commandDialog/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tamplate/commands/commandDialog/entry.py b/tamplate/commands/commandDialog/entry.py new file mode 100644 index 0000000..cafd41c --- /dev/null +++ b/tamplate/commands/commandDialog/entry.py @@ -0,0 +1,158 @@ +import adsk.core +import os +from ...lib import fusion360utils as futil +from ... import config +app = adsk.core.Application.get() +ui = app.userInterface + + +# TODO *** Specify the command identity information. *** +CMD_ID = f'{config.COMPANY_NAME}_{config.ADDIN_NAME}_cmdDialog' +CMD_NAME = 'Command Dialog Sample' +CMD_Description = 'A Fusion 360 Add-in Command with a dialog' + +# Specify that the command will be promoted to the panel. +IS_PROMOTED = True + +# TODO *** Define the location where the command button will be created. *** +# This is done by specifying the workspace, the tab, and the panel, and the +# command it will be inserted beside. Not providing the command to position it +# will insert it at the end. +WORKSPACE_ID = 'FusionSolidEnvironment' +PANEL_ID = 'SolidScriptsAddinsPanel' +COMMAND_BESIDE_ID = 'ScriptsManagerCommand' + +# Resource location for command icons, here we assume a sub folder in this directory named "resources". +ICON_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'resources', '') + +# Local list of event handlers used to maintain a reference so +# they are not released and garbage collected. +local_handlers = [] + + +# Executed when add-in is run. +def start(): + # Create a command Definition. + cmd_def = ui.commandDefinitions.addButtonDefinition(CMD_ID, CMD_NAME, CMD_Description, ICON_FOLDER) + + # Define an event handler for the command created event. It will be called when the button is clicked. + futil.add_handler(cmd_def.commandCreated, command_created) + + # ******** Add a button into the UI so the user can run the command. ******** + # Get the target workspace the button will be created in. + workspace = ui.workspaces.itemById(WORKSPACE_ID) + + # Get the panel the button will be created in. + panel = workspace.toolbarPanels.itemById(PANEL_ID) + + # Create the button command control in the UI after the specified existing command. + control = panel.controls.addCommand(cmd_def, COMMAND_BESIDE_ID, False) + + # Specify if the command is promoted to the main toolbar. + control.isPromoted = IS_PROMOTED + + +# Executed when add-in is stopped. +def stop(): + # Get the various UI elements for this command + workspace = ui.workspaces.itemById(WORKSPACE_ID) + panel = workspace.toolbarPanels.itemById(PANEL_ID) + command_control = panel.controls.itemById(CMD_ID) + command_definition = ui.commandDefinitions.itemById(CMD_ID) + + # Delete the button command control + if command_control: + command_control.deleteMe() + + # Delete the command definition + if command_definition: + command_definition.deleteMe() + + +# Function that is called when a user clicks the corresponding button in the UI. +# This defines the contents of the command dialog and connects to the command related events. +def command_created(args: adsk.core.CommandCreatedEventArgs): + # General logging for debug. + futil.log(f'{CMD_NAME} Command Created Event') + + # https://help.autodesk.com/view/fusion360/ENU/?contextId=CommandInputs + inputs = args.command.commandInputs + + # TODO Define the dialog for your command by adding different inputs to the command. + + # Create a simple text box input. + inputs.addTextBoxCommandInput('text_box', 'Some Text', 'Enter some text.', 1, False) + + # Create a value input field and set the default using 1 unit of the default length unit. + defaultLengthUnits = app.activeProduct.unitsManager.defaultLengthUnits + default_value = adsk.core.ValueInput.createByString('1') + inputs.addValueInput('value_input', 'Some Value', defaultLengthUnits, default_value) + + # TODO Connect to the events that are needed by this command. + futil.add_handler(args.command.execute, command_execute, local_handlers=local_handlers) + futil.add_handler(args.command.inputChanged, command_input_changed, local_handlers=local_handlers) + futil.add_handler(args.command.executePreview, command_preview, local_handlers=local_handlers) + futil.add_handler(args.command.validateInputs, command_validate_input, local_handlers=local_handlers) + futil.add_handler(args.command.destroy, command_destroy, local_handlers=local_handlers) + + +# This event handler is called when the user clicks the OK button in the command dialog or +# is immediately called after the created event not command inputs were created for the dialog. +def command_execute(args: adsk.core.CommandEventArgs): + # General logging for debug. + futil.log(f'{CMD_NAME} Command Execute Event') + + # TODO ******************************** Your code here ******************************** + + # Get a reference to your command's inputs. + inputs = args.command.commandInputs + text_box: adsk.core.TextBoxCommandInput = inputs.itemById('text_box') + value_input: adsk.core.ValueCommandInput = inputs.itemById('value_input') + + # Do something interesting + text = text_box.text + expression = value_input.expression + msg = f'Your text: {text}
Your value: {expression}' + ui.messageBox(msg) + + +# This event handler is called when the command needs to compute a new preview in the graphics window. +def command_preview(args: adsk.core.CommandEventArgs): + # General logging for debug. + futil.log(f'{CMD_NAME} Command Preview Event') + inputs = args.command.commandInputs + + +# This event handler is called when the user changes anything in the command dialog +# allowing you to modify values of other inputs based on that change. +def command_input_changed(args: adsk.core.InputChangedEventArgs): + changed_input = args.input + inputs = args.inputs + + # General logging for debug. + futil.log(f'{CMD_NAME} Input Changed Event fired from a change to {changed_input.id}') + + +# This event handler is called when the user interacts with any of the inputs in the dialog +# which allows you to verify that all of the inputs are valid and enables the OK button. +def command_validate_input(args: adsk.core.ValidateInputsEventArgs): + # General logging for debug. + futil.log(f'{CMD_NAME} Validate Input Event') + + inputs = args.inputs + + # Verify the validity of the input values. This controls if the OK button is enabled or not. + valueInput = inputs.itemById('value_input') + if valueInput.value >= 0: + args.areInputsValid = True + else: + args.areInputsValid = False + + +# This event handler is called when the command terminates. +def command_destroy(args: adsk.core.CommandEventArgs): + # General logging for debug. + futil.log(f'{CMD_NAME} Command Destroy Event') + + global local_handlers + local_handlers = [] diff --git a/tamplate/commands/commandDialog/resources/16x16.png b/tamplate/commands/commandDialog/resources/16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..03babdc056577fea50543b03d15c480d88c89f4c GIT binary patch literal 415 zcmV;Q0bu@#P)KA9k4D0+<1qc$SunL_18+0mJ|no~1oAf13dfUQ*u%01+5>;@Y z)*+9ui?QG#{8m7wjtRZ_7;GpXT!7Xr);$MsL(ih)&$~U6?q5HKp5f86w1-XuNy<+m ziM)=y6Z(%>u-E%a+b3{!z~(0Dcce}w4hGl2o zy!Y*!_hU9;+cvg|2T^S6rX^)vFJ%&8b=}+Q=c_!Rn^p=y6@XDMWu{S-Z=yr$0lx7w zfD`uQ?@^2g>JWm^v+>X~-24*Dhu;%x1PJ3R3<2zK=m1JqAmKlP zDq$QUjH_f1xeXV70tRP!SLksYasu2n+8vPyj)4_;EL;NEjmh{7Ku(s5R3S27}iUf9JR=g?(3!*!+J;9 zUT_wma2h1zM_2-vG0C{tdN&M9fIR<@GLZ?KsX8NH3l#%YA*w1m9+ieEZyG*X{=mcA zg}c6U`{&Ev_0^}zWO8K~#>XH6%#Gg_#E1M#R{@vf?{50-efxleXHSKVola*wo6X)d z8jW}Cohn3AUOuU6$P8U52s$Vhi^5#D+huOKD3{A%Bm@GUJ3(B1fPzC}jX=PKBo-VW zYmdg`k<&K@gTY(B2UHi5Sa5Xo;xPa=P^;C17+}rfd7M|WX0wUWXe0>a^LgjFMu4T3 zZdzI#m(ql7{{(Pf(=;p=3qdfQPNU!Ni&-Ec;l0VQVd$nMB~UMA+;&^(-TY>OoXuuc zo|31bhs6KCB90w|u j%CBTHsr;pz&*%6H8=VB7i~>0q00000NkvXXu0mjfNzF8J literal 0 HcmV?d00001 diff --git a/tamplate/commands/commandDialog/resources/64x64.png b/tamplate/commands/commandDialog/resources/64x64.png new file mode 100644 index 0000000000000000000000000000000000000000..dd285fd1c9a47ff154e426da5c90fcdd96239c2c GIT binary patch literal 1077 zcmV-51j_q~P)ZWvYv= zx{iE7uCu6eC_iv#i2_oDd_h3U2V4qV&?G1gA|e+p8iVi7XYZ_c_iU3VU16PXXWqN@ z?9A+XW-u7wA!GJIvj_0lmLWfkSW_)^9A4)TT$bSUz1i%S7VI6)LtqJ=8o~!!779c@B##BTgKfaKCsQSSY zAccGkt0L(1Lpl@8Fq*{WXiOky8UVIrog(z;+3p6e^Q)*IlOQF4q|v1DB@vW}_)E#( zW#It8o*>2aBUgl60hr{=hFlRc1)%ABk_a@l6JcTy^uuVr2ILV3#z|jJ6o3Lx!p^A!-OI|=a6RemBQsf0#sW1)tPT4Ix zkR~snQVxss^n(T}KLGR-*Gp8@6~)9QFAXXJ>=krSq_yp|#KaFHA;LB-TdMiT9*rRd zR$H8sqo0b7oe9Te3KX&(b;MNus$f&v&$~x}+qY-nP2f7Lz?1|%4t?D)7bTX)8G~s7-qHr9GAI)?)||C*KA=q`RM9orn&+0o z9fdtUs1`&8>>W@cl?$!_VyEbvf<6Td zj*eLOZ)|J~U1tg)c3J%}LYYN4K0apMKPrHU6Cxtzd_}*})fg4&^9vK_6Qq_w#!N^a zNfV!r=98iw?{L_M_4Re;u)~n91tdgBJ&#A%+kP0a1PEM5s+~4ErMXZ!A(A!?rO)P; z4eVklA;M+V$qOjGF+z{SDdh=`X_7a(3}!))77YxQeSe)Wz6@qz+T?Y>+KZE>U~L&J vE37Vqb%eDUVC!9AE-Lr>yytoP90u?YjV+lgrL2(V00000NkvXXu0mjf+LYiK literal 0 HcmV?d00001 diff --git a/tamplate/commands/paletteSend/__init__.py b/tamplate/commands/paletteSend/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tamplate/commands/paletteSend/entry.py b/tamplate/commands/paletteSend/entry.py new file mode 100644 index 0000000..0878e66 --- /dev/null +++ b/tamplate/commands/paletteSend/entry.py @@ -0,0 +1,149 @@ +import json +import adsk.core +import os +from ...lib import fusion360utils as futil +from ... import config + +app = adsk.core.Application.get() +ui = app.userInterface + +# TODO ********************* Change these names ********************* +CMD_ID = f'{config.COMPANY_NAME}_{config.ADDIN_NAME}_palette_send' +CMD_NAME = 'Send to Palette' +CMD_Description = 'Send some information to the palette' +IS_PROMOTED = False + +# Using "global" variables by referencing values from /config.py +PALETTE_ID = config.sample_palette_id + +# TODO *** Define the location where the command button will be created. *** +# This is done by specifying the workspace, the tab, and the panel, and the +# command it will be inserted beside. Not providing the command to position it +# will insert it at the end. +WORKSPACE_ID = 'FusionSolidEnvironment' +PANEL_ID = 'SolidScriptsAddinsPanel' +COMMAND_BESIDE_ID = 'ScriptsManagerCommand' + +# Resource location for command icons, here we assume a sub folder in this directory named "resources". +ICON_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'resources', '') + +# Local list of event handlers used to maintain a reference so +# they are not released and garbage collected. +local_handlers = [] + + +# Executed when add-in is run. +def start(): + # Create a command Definition. + cmd_def = ui.commandDefinitions.addButtonDefinition(CMD_ID, CMD_NAME, CMD_Description, ICON_FOLDER) + + # Add command created handler. The function passed here will be executed when the command is executed. + futil.add_handler(cmd_def.commandCreated, command_created) + + # ******** Add a button into the UI so the user can run the command. ******** + # Get the target workspace the button will be created in. + workspace = ui.workspaces.itemById(WORKSPACE_ID) + + # Get the panel the button will be created in. + panel = workspace.toolbarPanels.itemById(PANEL_ID) + + # Create the button command control in the UI after the specified existing command. + control = panel.controls.addCommand(cmd_def, COMMAND_BESIDE_ID, False) + + # Specify if the command is promoted to the main toolbar. + control.isPromoted = IS_PROMOTED + + +# Executed when add-in is stopped. +def stop(): + # Get the various UI elements for this command + workspace = ui.workspaces.itemById(WORKSPACE_ID) + panel = workspace.toolbarPanels.itemById(PANEL_ID) + command_control = panel.controls.itemById(CMD_ID) + command_definition = ui.commandDefinitions.itemById(CMD_ID) + + # Delete the button command control + if command_control: + command_control.deleteMe() + + # Delete the command definition + if command_definition: + command_definition.deleteMe() + + +# Event handler that is called when the user clicks the command button in the UI. +# To have a dialog, you create the desired command inputs here. If you don't need +# a dialog, don't create any inputs and the execute event will be immediately fired. +# You also need to connect to any command related events here. +def command_created(args: adsk.core.CommandCreatedEventArgs): + # General logging for debug. + futil.log(f'{CMD_NAME} Command Created Event') + + # TODO Create the event handlers you will need for this instance of the command + futil.add_handler(args.command.execute, command_execute, local_handlers=local_handlers) + futil.add_handler(args.command.inputChanged, command_input_changed, local_handlers=local_handlers) + futil.add_handler(args.command.executePreview, command_preview, local_handlers=local_handlers) + futil.add_handler(args.command.destroy, command_destroy, local_handlers=local_handlers) + + # Create the user interface for your command by adding different inputs to the CommandInputs object + # https://help.autodesk.com/view/fusion360/ENU/?contextId=CommandInputs + inputs = args.command.commandInputs + + # TODO ******************************** Define your UI Here ******************************** + + # Simple text input box + inputs.addTextBoxCommandInput('text_input', 'Text Message', 'Enter some text', 1, False) + + # To create a numerical input with units, we need to get the current units and create a "ValueInput" + # https://help.autodesk.com/view/fusion360/ENU/?contextId=ValueInput + users_current_units = app.activeProduct.unitsManager.defaultLengthUnits + default_value = adsk.core.ValueInput.createByString(f'1 {users_current_units}') + inputs.addValueInput('value_input', 'Value Message', users_current_units, default_value) + + +# This function will be called when the user hits the OK button in the command dialog +def command_execute(args: adsk.core.CommandEventArgs): + # General logging for debug + futil.log(f'{CMD_NAME} Command Execute Event') + + inputs = args.command.commandInputs + + # TODO ******************************** Your code here ******************************** + + # Get a reference to your command's inputs + text_input: adsk.core.TextBoxCommandInput = inputs.itemById('text_input') + value_input: adsk.core.ValueCommandInput = inputs.itemById('value_input') + + # Construct a message + message_action = 'updateMessage' + message_data = { + 'myValue': f'{value_input.value} cm', + 'myExpression': value_input.expression, + 'myText': text_input.formattedText + } + # JSON strings are a useful way to translate between javascript objects and python dictionaries + message_json = json.dumps(message_data) + + # Get a reference to the palette and send the message to the palette javascript + palette = ui.palettes.itemById(PALETTE_ID) + palette.sendInfoToHTML(message_action, message_json) + + +# This function will be called when the command needs to compute a new preview in the graphics window +def command_preview(args: adsk.core.CommandEventArgs): + inputs = args.command.commandInputs + futil.log(f'{CMD_NAME} Command Preview Event') + + +# This function will be called when the user changes anything in the command dialog +def command_input_changed(args: adsk.core.InputChangedEventArgs): + changed_input = args.input + inputs = args.inputs + futil.log(f'{CMD_NAME} Input Changed Event fired from a change to {changed_input.id}') + + +# This event handler is called when the command terminates. +def command_destroy(args: adsk.core.CommandEventArgs): + global local_handlers + local_handlers = [] + futil.log(f'{CMD_NAME} Command Destroy Event') diff --git a/tamplate/commands/paletteSend/resources/16x16.png b/tamplate/commands/paletteSend/resources/16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..c18250a935fb739d5651b499e03ede8a65f0e9b4 GIT binary patch literal 474 zcmV<00VV#4P)K+Q5MPI7Ji_pD7rS1AX{v<5J6%g zscbC$0a_T?EiDzIVAvTaA2Z{z7>S8SOb#5*xrck+``lLnrhzD}#kq*20aPF=BC%<0 zwdw6YsV#u20O4@BMS#~(0dl!qOG}EP)C)My6SnO%_oCYNp1`tfils7h*)9O~C-e^m zI=vn51ZkQY#WjHv>pc^K-VXo_j8PyH5?m;$~w*vNkl&LL&Z|T3T-5HDV18fX^oZCv_?%V z>j$>d7V_eQv{1A)U_Yp}YJ-%bplN8@qQ$h$=O#90=YIIGGm~s~b~j799=LG1bC~m+ z|2gN*y#`(&@mcZL>ab~ap z1(Z?I{+)5ZcGCJ?EIED?Rq~J&In-J@DwB@+!_Z5V0tSF#=5)a{@F#GGd6xzclR&~A*$T!2Lkk5*_O?t~_iq0% zF>t)o4t|Gun^7U`p^9bej#V#jnW$L0_9XBWP{X_wYppQ~1W*Ai1s()ON#@*@{r>>) l1EnNuYKCO(q{*(e=06uyS_{OSTi^fy002ovPDHLkV1h6_?}z{Z literal 0 HcmV?d00001 diff --git a/tamplate/commands/paletteSend/resources/64x64.png b/tamplate/commands/paletteSend/resources/64x64.png new file mode 100644 index 0000000000000000000000000000000000000000..ed1ae276ca4eb5a06999f3e340cabec2f571653a GIT binary patch literal 1972 zcmV;l2TS;gP)P|5NA&mlJKR z&5-rUiU3anqGn@N%V=cMnVd%X^-719(I87e8jm4u9|9^6O=}qzGU=Q~`SnUiTFZdE zsVdSpPXZtt1raL(28T|CZD(jOBOrqG$y3nn1SkOe_ue0-ZOe@%Q@WaeV0vZ-P18fO zXgQ#&QC6r0t~s~OKOh7chUeU&;vsyP??8Zf4-ini{mujk*NIbAARqz%9|9PLdjuT+ zb1nb4m_2Rt8jUZ1bk3iJAtU$@@Q47r^H#mmBBl%k_|pKV_7DBK!B-!C@$_9O*WZ?1 z1Dx95z9HOU;bmi}8nCf7&A&!#a_Ua)Kk>oY;;kqFUO^go2--i!a0CeRY0yt6PEU`UHf}8X z{8Hfd#Og*syrTzzF^ zO$}Ibe-Ox5$T_eypc+af5?xSZt(}Jkjx?&V*3Ng*H}2^D`tC1^Tmn2va3P>NN+c4| z0Sp1(?H_1TYvbF`&)smx?ymdpHXV1}8e^d>S>S3xShrfh^gKM77-;%t&z>ExUr^J) zV}Oo-0=z|V_>Ezb$>d@^9*@(}-Vwl!;4pyE85s%RNena{*t_SBrklPrKk@gUJiOGo zzBRz^JU}v;ylNUCZ<0`iAs0bLry+F(4n95599>cO>E#<(INDe0ohJ@?>0AB<+>?ioZ`s-cWzkKTFrx#Xj+o{Ilw-$Yo zJX}N(^_#Z=0z>4!oVheDhr`29^~WFI*R!joy-SR}akLk?WiE#V-x|=|)WZ10SWew3 z0@hu(-qrY6tZrdOZSDN__Xir6^t1>}Tq%4zH8LfS9XOO|ec~HE_q4Qk;Y5P(A+YJg zHx(T7`zA?IvgzyJmwcV-3nNof8+yN&XzknYOhSPOf+Qi#g2}#agkLUB!T4p^|74<7 ziPYTF(%#hvtiaqr>6`^ZE;3$(q6^TB@XLiM7{3Dh`XmX+jp0#1anu0eGYj~I5Hj)% zV|m^zU%MJsUjt9|?in{Sv%f+TkOs6u0ua6y6oSBtfH2Xv8dlfB;csIvlU{zf$qYE+uHe4ILzlm8Xc=>3nhx%Ih;eqayJ~#Htl`WrXy+7+#-zpES_cON`j^UvIsI@Z)fQym<6 zq&ua}jh#uI8#)3^0u#U#Fb8PXF7a!CRX`)q0MsGJiDQ;15gL%Oeb(5@3jC36*&S`! zy8D^0K60eNPJre7vyUx0|05uUBw!ktMQVVdB11t37J$oUAM+&`wG?!u^HvC|<~3@_ z{%@gJM9gznVy=Q)V!E~g8e)#lr+^vcozIvy2#Wv>NdV@LDn;zI_X+zD5N7}O;^$gc z)YgF_2@qN5k3H__y#3DS%ml54gS72)Q6+=>+Z2!_XdowV z&-ZmtYI9>}y_}DC^oS*w#g`Kgb?+_pR4ZCFePR04^L=~n)aNH&N}U@zhD>pe&O3Ef zt^W|UG{8#TF{Cf^NXKXJ2zxuCVOts!>;eihbIl>s_+|6^lFq|b9s&VirS5s;P>7nx zGDycW6yZEn?+~y@K-B!SCUo|>eo-A&E9@y$A?vWOZ1z76&6OwtiJT<>0000Action: {message_action}
arg1: {arg1}
arg2: {arg2}' + ui.messageBox(msg) + + # Return value. + now = datetime.now() + currentTime = now.strftime('%H:%M:%S') + html_args.returnData = f'OK - {currentTime}' + + +# This event handler is called when the command terminates. +def command_destroy(args: adsk.core.CommandEventArgs): + # General logging for debug. + futil.log(f'{CMD_NAME}: Command destroy event.') + + global local_handlers + local_handlers = [] diff --git a/tamplate/commands/paletteShow/resources/16x16.png b/tamplate/commands/paletteShow/resources/16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..f1b8e5705f6c5544667a8ea92580d82360687e34 GIT binary patch literal 340 zcmV-a0jvIrP);xMdD{U>TEPR43wo$aQ@EP(1mX;P~ zGMS&mVj&Yl2)nu6z&(fijR%Z?9^LX80KK9p&PP|bbJNd{_XGe@6m=ZHR1n8;C)o46 zsleJCo9A=E3%>6bXl>BOa5-Kn3r|DQDp(8xC&;uxN(DH9NEO#F8;$V8*$-ie6DXw- zsr*+GspPKz-6#+#_`X+JkZBSjx!L_HOG*0$wG)))H<7JCJ literal 0 HcmV?d00001 diff --git a/tamplate/commands/paletteShow/resources/32x32.png b/tamplate/commands/paletteShow/resources/32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..a61a47e4710bdc2aedde29ee1f9f4f0b25d8c82a GIT binary patch literal 587 zcmV-R0<`^!P)do&Mr37>Z`J(s>*sC z{uEW5lPmy5Q8X}Nppp-uDs>t_R9Y#xw=v&xdUjzq8Nfa*I{-wZJ0Rum5b275DAx9; zAbh+3?!X|?C+C0s3qY{8f0g0ez)sSn$Cz4c8X!cV55O1b z+Uqxigl}EH)&TTv!$|~S;sI`4xjYCU_}2ivMd(mZaP`u~)&!{v)ELuKgsMzj128Ky z#^5w^66OGio`eD5?T7a*$JOzB)jy9n!+EC8H1eyTM=s&=hE1=F2 z78efB9>8nu1rT6+>FAODdx2(b7T5;F0Q0~h;2`xoF^ByEz5-ti^&4%@ix)AkgeD&1 Z=Wl;YQq&g|YVQC5002ovPDHLkV1iU;1q1*9 literal 0 HcmV?d00001 diff --git a/tamplate/commands/paletteShow/resources/64x64.png b/tamplate/commands/paletteShow/resources/64x64.png new file mode 100644 index 0000000000000000000000000000000000000000..4dd5dfcb2d51b5651ff4fcc8a4f757af32a172a5 GIT binary patch literal 1165 zcmV;81akX{P)% z&x;&I6vscc+pd`ng1BxNLQoO|akDB}6N3aJNOV0Y2oeY$)=NSlC&i2Zh2SY5@nQrC zFIn=)32v$-uuq`Rozv} z7{k*H4?roU00o=@PDG!Z2m@RLE&#?DW4!2w0(Jl&UcB_{r{mJD3ap&^$OC=^9syef zc)(7e73hG@>N+1Uzq2*y%GEzASF{YYcg+E`2yOL&UQEC=FbnMP`#$|%e_-J7^`ye@ z`w)8iEbtJb8~{uKGl19g`#kRV1_lmaPbzwTA3~dF2yNaXfJmTX54d>gO7$9+jK~8N zk?}A{003Wqd8R^@#*YL68ygStgJ2xGln!rt8qb>^lnsB$7=zKxY>v!S(yk-{fNp4a zC|Q*t0Apxudo0)`gaGKKhJav}m;LtktA zoISR=O%=<9eF&KB5EwQ-mgS8bH|#>d80RD?jr;1C=bh$q!8f1$n|a@o0QV{&jaxoY zU0CGlU3wLe#=XD4>ok|!?`Pj1SqLob>T!2&Pq~DLBke_s=EQXB8Rvsh| zII?u8_(YD#O5RG@hJZHcKxY!rYPHzh+)T)HP~RM&l)TJOO@dhjteiS2%Ilm2?L8ps z1e^9yC?p^$7d;@z@qkH00S_<@_JBeJq%-jQ^&8xO@L)i;XZLR2d-wPVR4oTesbZaA z76HS?$Fh1SL2ClY^?)=;b@->tmkZD1iqB5U)d>nDK^-lJT?mkt(TfKc3eV$;tYy4H zA@#RTIUo&^2P_W=kptT8Hl0oO(520#YCF@=JRQ z&*O>_b%N1m$qWMKUU-r9fBsI$>Rvgl-wo#FfW^hvMR}b!SA{vistS->1ttkmiq+V%V3>hT?T2e2S{0PD)Aj;SDADeBfsz!li;DnSIXCD9LPz68o2%D8~dLF zo<;DE35NzA1Gl5kz!L&A&;x!3{sQKJXDU{(Z1jP3;2xo^8lDgk09{};x?U$dOV}g? zzy_g>-RK%+j6o?iMR=faC*h&Ot#fq^LhR*T;6LDzF-FG(#D}Ln!hgPL#>dcv|GZCh fcv>~F + + + + Title + + + +
+ +

Fusion 360 Palette Sample

+ +

+ +

Send Data to HTML Event Handler

+
+ +

+ +
+ +

HTML Event Response Value:

+
Response
+ +

Message from "Send to Palette" Command

+
+

Message from Fusion

+

+
+ +
+ + diff --git a/tamplate/commands/paletteShow/resources/html/static/palette.js b/tamplate/commands/paletteShow/resources/html/static/palette.js new file mode 100644 index 0000000..dacdafc --- /dev/null +++ b/tamplate/commands/paletteShow/resources/html/static/palette.js @@ -0,0 +1,48 @@ +function getDateString() { + const today = new Date(); + const date = `${today.getDate()}/${today.getMonth() + 1}/${today.getFullYear()}`; + const time = `${today.getHours()}:${today.getMinutes()}:${today.getSeconds()}`; + return `Date: ${date}, Time: ${time}`; +} + +function sendInfoToFusion() { + const args = { + arg1: document.getElementById("sampleData").value, + arg2: getDateString() + }; + + // Send the data to Fusion as a JSON string. The return value is a Promise. + adsk.fusionSendData("messageFromPalette", JSON.stringify(args)).then((result) => + document.getElementById("returnValue").innerHTML = `${result}` + ); + +} + +function updateMessage(messageString) { + // Message is sent from the add-in as a JSON string. + const messageData = JSON.parse(messageString); + + // Update a paragraph with the data passed in. + document.getElementById("fusionMessage").innerHTML = + `Your text: ${messageData.myText}
` + + `Your expression: ${messageData.myExpression}
` + + `Your value: ${messageData.myValue}`; +} + +window.fusionJavaScriptHandler = { + handle: function (action, data) { + try { + if (action === "updateMessage") { + updateMessage(data); + } else if (action === "debugger") { + debugger; + } else { + return `Unexpected command type: ${action}`; + } + } catch (e) { + console.log(e); + console.log(`Exception caught with command: ${action}, data: ${data}`); + } + return "OK"; + }, +}; diff --git a/tamplate/config.py b/tamplate/config.py new file mode 100644 index 0000000..774f687 --- /dev/null +++ b/tamplate/config.py @@ -0,0 +1,21 @@ +# Application Global Variables +# This module serves as a way to share variables across different +# modules (global variables). + +import os + +# Flag that indicates to run in Debug mode or not. When running in Debug mode +# more information is written to the Text Command window. Generally, it's useful +# to set this to True while developing an add-in and set it to False when you +# are ready to distribute it. +DEBUG = True + +# Gets the name of the add-in from the name of the folder the py file is in. +# This is used when defining unique internal names for various UI elements +# that need a unique name. It's also recommended to use a company name as +# part of the ID to better ensure the ID is unique. +ADDIN_NAME = os.path.basename(os.path.dirname(__file__)) +COMPANY_NAME = 'ACME' + +# Palettes +sample_palette_id = f'{COMPANY_NAME}_{ADDIN_NAME}_palette_id' \ No newline at end of file diff --git a/tamplate/lib/fusion360utils/__init__.py b/tamplate/lib/fusion360utils/__init__.py new file mode 100644 index 0000000..56e95d5 --- /dev/null +++ b/tamplate/lib/fusion360utils/__init__.py @@ -0,0 +1,2 @@ +from .general_utils import * +from .event_utils import * diff --git a/tamplate/lib/fusion360utils/event_utils.py b/tamplate/lib/fusion360utils/event_utils.py new file mode 100644 index 0000000..97a09b0 --- /dev/null +++ b/tamplate/lib/fusion360utils/event_utils.py @@ -0,0 +1,88 @@ +# Copyright 2022 by Autodesk, Inc. +# Permission to use, copy, modify, and distribute this software in object code form +# for any purpose and without fee is hereby granted, provided that the above copyright +# notice appears in all copies and that both that copyright notice and the limited +# warranty and restricted rights notice below appear in all supporting documentation. +# +# AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. AUTODESK SPECIFICALLY +# DISCLAIMS ANY IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. +# AUTODESK, INC. DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +# UNINTERRUPTED OR ERROR FREE. + +import sys +from typing import Callable + +import adsk.core +from .general_utils import handle_error + + +# Global Variable to hold Event Handlers +_handlers = [] + + +def add_handler( + event: adsk.core.Event, + callback: Callable, + *, + name: str = None, + local_handlers: list = None +): + """Adds an event handler to the specified event. + + Arguments: + event -- The event object you want to connect a handler to. + callback -- The function that will handle the event. + name -- A name to use in logging errors associated with this event. + Otherwise the name of the event object is used. This argument + must be specified by its keyword. + local_handlers -- A list of handlers you manage that is used to maintain + a reference to the handlers so they aren't released. + This argument must be specified by its keyword. If not + specified the handler is added to a global list and can + be cleared using the clear_handlers function. You may want + to maintain your own handler list so it can be managed + independently for each command. + + :returns: + The event handler that was created. You don't often need this reference, but it can be useful in some cases. + """ + module = sys.modules[event.__module__] + handler_type = module.__dict__[event.add.__annotations__['handler']] + handler = _create_handler(handler_type, callback, event, name, local_handlers) + event.add(handler) + return handler + + +def clear_handlers(): + """Clears the global list of handlers. + """ + global _handlers + _handlers = [] + + +def _create_handler( + handler_type, + callback: Callable, + event: adsk.core.Event, + name: str = None, + local_handlers: list = None +): + handler = _define_handler(handler_type, callback, name)() + (local_handlers if local_handlers is not None else _handlers).append(handler) + return handler + + +def _define_handler(handler_type, callback, name: str = None): + name = name or handler_type.__name__ + + class Handler(handler_type): + def __init__(self): + super().__init__() + + def notify(self, args): + try: + callback(args) + except: + handle_error(name) + + return Handler diff --git a/tamplate/lib/fusion360utils/general_utils.py b/tamplate/lib/fusion360utils/general_utils.py new file mode 100644 index 0000000..fcf2667 --- /dev/null +++ b/tamplate/lib/fusion360utils/general_utils.py @@ -0,0 +1,64 @@ +# Copyright 2022 by Autodesk, Inc. +# Permission to use, copy, modify, and distribute this software in object code form +# for any purpose and without fee is hereby granted, provided that the above copyright +# notice appears in all copies and that both that copyright notice and the limited +# warranty and restricted rights notice below appear in all supporting documentation. +# +# AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. AUTODESK SPECIFICALLY +# DISCLAIMS ANY IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. +# AUTODESK, INC. DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +# UNINTERRUPTED OR ERROR FREE. + +import os +import traceback +import adsk.core + +app = adsk.core.Application.get() +ui = app.userInterface + +# Attempt to read DEBUG flag from parent config. +try: + from ... import config + DEBUG = config.DEBUG +except: + DEBUG = False + + +def log(message: str, level: adsk.core.LogLevels = adsk.core.LogLevels.InfoLogLevel, force_console: bool = False): + """Utility function to easily handle logging in your app. + + Arguments: + message -- The message to log. + level -- The logging severity level. + force_console -- Forces the message to be written to the Text Command window. + """ + # Always print to console, only seen through IDE. + print(message) + + # Log all errors to Fusion log file. + if level == adsk.core.LogLevels.ErrorLogLevel: + log_type = adsk.core.LogTypes.FileLogType + app.log(message, level, log_type) + + # If config.DEBUG is True write all log messages to the console. + if DEBUG or force_console: + log_type = adsk.core.LogTypes.ConsoleLogType + app.log(message, level, log_type) + + +def handle_error(name: str, show_message_box: bool = False): + """Utility function to simplify error handling. + + Arguments: + name -- A name used to label the error. + show_message_box -- Indicates if the error should be shown in the message box. + If False, it will only be shown in the Text Command window + and logged to the log file. + """ + + log('===== Error =====', adsk.core.LogLevels.ErrorLogLevel) + log(f'{name}\n{traceback.format_exc()}', adsk.core.LogLevels.ErrorLogLevel) + + # If desired you could show an error as a message box. + if show_message_box: + ui.messageBox(f'{name}\n{traceback.format_exc()}') diff --git a/tamplate/tamplate.manifest b/tamplate/tamplate.manifest new file mode 100644 index 0000000..1ca7de4 --- /dev/null +++ b/tamplate/tamplate.manifest @@ -0,0 +1,13 @@ +{ + "autodeskProduct": "Fusion360", + "type": "addin", + "id": "f1a3be42-3a4c-4ea3-9b2d-86ad07c09291", + "author": "", + "description": { + "": "" + }, + "version": "", + "runOnStartup": false, + "supportedOS": "windows|mac", + "editEnabled": true +} \ No newline at end of file diff --git a/tamplate/tamplate.py b/tamplate/tamplate.py new file mode 100644 index 0000000..3695089 --- /dev/null +++ b/tamplate/tamplate.py @@ -0,0 +1,24 @@ +# Assuming you have not changed the general structure of the template no modification is needed in this file. +from . import commands +from .lib import fusion360utils as futil + + +def run(context): + try: + # This will run the start function in each of your commands as defined in commands/__init__.py + commands.start() + + except: + futil.handle_error('run') + + +def stop(context): + try: + # Remove all of the event handlers your app has created + futil.clear_handlers() + + # This will run the start function in each of your commands as defined in commands/__init__.py + commands.stop() + + except: + futil.handle_error('stop') \ No newline at end of file diff --git a/zoom_test/.env b/zoom_test/.env new file mode 100644 index 0000000..6aedf1e --- /dev/null +++ b/zoom_test/.env @@ -0,0 +1 @@ +PYTHONPATH=C:/Users/bartool/AppData/Local/Autodesk/webdeploy/production/9209df45963e1599ff476303834125d21fd43de4/Api/Python/packages diff --git a/zoom_test/.vscode/launch.json b/zoom_test/.vscode/launch.json new file mode 100644 index 0000000..1c69300 --- /dev/null +++ b/zoom_test/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + "version": "0.2.0", + "configurations": [{ + "name": "Python: Attach", + "type": "python", + "request": "attach", + "pathMappings": [{ + "localRoot": "${workspaceRoot}", + "remoteRoot": "${workspaceRoot}" + }], + "osx": { + "filePath": "${file}" + }, + "windows": { + "filePath": "${file}" + }, + "port": 9000, + "host": "localhost" + }] +} \ No newline at end of file diff --git a/zoom_test/.vscode/settings.json b/zoom_test/.vscode/settings.json new file mode 100644 index 0000000..1c5eab8 --- /dev/null +++ b/zoom_test/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "python.autoComplete.extraPaths": ["C:/Users/bartool/AppData/Roaming/Autodesk/Autodesk Fusion 360/API/Python/defs"], + "python.analysis.extraPaths": ["C:/Users/bartool/AppData/Roaming/Autodesk/Autodesk Fusion 360/API/Python/defs"], + "python.pythonPath": "C:/Users/bartool/AppData/Local/Autodesk/webdeploy/production/9209df45963e1599ff476303834125d21fd43de4/Python/python.exe" +} \ No newline at end of file diff --git a/zoom_test/zoom_test.manifest b/zoom_test/zoom_test.manifest new file mode 100644 index 0000000..28ab33c --- /dev/null +++ b/zoom_test/zoom_test.manifest @@ -0,0 +1,10 @@ +{ + "autodeskProduct": "Fusion360", + "type": "script", + "author": "", + "description": { + "": "" + }, + "supportedOS": "windows|mac", + "editEnabled": true +} \ No newline at end of file diff --git a/zoom_test/zoom_test.py b/zoom_test/zoom_test.py new file mode 100644 index 0000000..817697e --- /dev/null +++ b/zoom_test/zoom_test.py @@ -0,0 +1,65 @@ +# Author- +# Description- + +import adsk.core +import adsk.fusion +import adsk.cam +import traceback + + +def run(context): + ui = None + try: + app = adsk.core.Application.get() + ui = app.userInterface + + zoom_camera(app, app.activeViewport) + # ui.messageBox('Hello script') + + except: + if ui: + ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) + + +def zoom_camera(app: adsk.core.Application, view: adsk.core.Viewport): + try: + camera = view.camera + eye = camera.eye + target = camera.target + + eye_x = eye.x + eye_y = eye.y + eye_z = eye.z + + tgt_x = target.x + tgt_y = target.y + tgt_z = target.z + + eye_tgt_vector = eye.vectorTo(target) + + eye_tgt_vector.scaleBy(0.5) + + new_x = eye_tgt_vector.asPoint().x + new_y = eye_tgt_vector.asPoint().y + new_z = eye_tgt_vector.asPoint().z + # eye.set(eye_x - new_x, eye_y - new_y, eye_z - new_z) + eye = adsk.core.Point3D.create( + eye_x - new_x, eye_y - new_y, eye_z - new_z) + # eye.translateBy(eye_tgt_vector) + eye = adsk.core.Point3D.create(100, 100, 100) + camera.eye = eye + fit = camera.isFitView + base = camera.viewExtents + base = base*2 + camera.viewExtents = base + view.camera = camera + view.refresh() + + ui = app.userInterface + ui.messageBox('Eye: {0}, {1}, {2} \ntarget: {3}, {4}, {5}'.format( + eye.x, eye.y, eye.z, target.x, target.y, target.z)) + + except: + ui = app.userInterface + if ui: + ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))