Repository navigation
Expand file tree
/
Copy pathThreadMeister.py
More file actions
102 lines (84 loc) · 3.57 KB
/
Copy pathThreadMeister.py
File metadata and controls
102 lines (84 loc) · 3.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
"""
ThreadMeister – Heat-set Insert Creator for Fusion 360
Copyright (c) 2026 Andreas Kircher
SPDX-License-Identifier: MIT
This add-in automates the creation of heat-set insert holes for 3D printing,
using the dimensional specifications from CNC Kitchen.
Author: Andreas Kircher (Andreas.O.Kircher@gmail.com)
Created with assistance from: Claude (Anthropic) / Perplexity
Insert specifications from: CNC Kitchen (cnckitchen.com)
Version: 1.2.5
Features:
- Creates heat-set insert holes at sketch points
- Hole creation with CNC Kitchen specifications (M2-M10, 1/4"-20) – customizable via config.ini
- Blind holes and through holes
- Automatic chamfer for easier insert installation
- Automatic bottom radius for blind holes
- Timeline grouping for easy management
- Direct subtraction from target body
- Clean temp sketch approach for reliable profile selection
Usage:
1. Create a sketch with points where you want insert holes
2. Click "ThreadMeister" button in SOLID > MODIFY menu
3. Select target body and sketch points
4. Choose insert size and options
5. Done!
Known Issues:
- Not tested with Apple macOS
- Overlapping bores may cause incomplete extrusions (no chamfer/radius)
"""
import traceback
import os
# Relative imports: Fusion loads every add-in under a name derived from its install path,
# so our modules stay separate from those of any other installed ThreadMeister copy
# (.scratch/duplicate-install/). Don't add core/ to sys.path.
from .core import tm_state
from .core import tm_config
from .core.tm_ui import CommandCreatedHandler
def run(context):
"""Called when the add-in is loaded."""
try:
tm_config.load_config()
cmdDefs = tm_state._ui.commandDefinitions
addon_path = os.path.dirname(os.path.realpath(__file__))
resources_path = os.path.join(addon_path, 'resources', 'icons')
# Another ThreadMeister copy loaded first and owns the button: take it over
existingDef = cmdDefs.itemById(tm_state.CMD_ID)
if existingDef:
panel = tm_state._ui.allToolbarPanels.itemById(tm_state.PANEL_ID)
if panel:
existingControl = panel.controls.itemById(tm_state.CMD_ID)
if existingControl:
existingControl.deleteMe()
existingDef.deleteMe()
buttonDef = cmdDefs.addButtonDefinition(
tm_state.CMD_ID,
tm_state.CMD_NAME,
tm_state.CMD_Description,
resources_path
)
onCommandCreated = CommandCreatedHandler()
buttonDef.commandCreated.add(onCommandCreated)
tm_state._handlers.append(onCommandCreated)
panel = tm_state._ui.allToolbarPanels.itemById(tm_state.PANEL_ID)
if panel:
buttonControl = panel.controls.addCommand(buttonDef)
buttonControl.isPromoted = True
buttonControl.isPromotedByDefault = True
else:
tm_state._ui.messageBox(f'Could not find panel: {tm_state.PANEL_ID}')
except Exception:
tm_state._ui.messageBox('Failed to load add-in:\n{}'.format(traceback.format_exc()))
def stop(context):
"""Called when the add-in is unloaded."""
try:
cmdDef = tm_state._ui.commandDefinitions.itemById(tm_state.CMD_ID)
if cmdDef:
cmdDef.deleteMe()
panel = tm_state._ui.allToolbarPanels.itemById(tm_state.PANEL_ID)
if panel:
control = panel.controls.itemById(tm_state.CMD_ID)
if control:
control.deleteMe()
except Exception:
tm_state._ui.messageBox('Failed to stop add-in:\n{}'.format(traceback.format_exc()))