forked from BalzGuenat/CustomThreads
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathExpanded_3DPrintable_CustomThreads.py
More file actions
161 lines (132 loc) Β· 5.66 KB
/
Copy pathExpanded_3DPrintable_CustomThreads.py
File metadata and controls
161 lines (132 loc) Β· 5.66 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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# ============================================================
# π USER INPUT SECTION β START HERE
# Change the values below to customize your thread generation
# ============================================================
# π§ Pitch range settings (in millimeters)
pitch_start = 1.0 # Starting pitch value (e.g., 1.0 mm)
pitch_end = 6.0 # Ending pitch value (e.g., 6.0 mm)
pitch_step = 0.5 # Interval between pitches (e.g., 0.5 mm)
# π Thread diameters to include (in millimeters)
thread_sizes = list(range(8, 51)) # Diameters from 8 mm to 50 mm
# βοΈ Tolerance offsets to simulate different thread classes
tolerance_offsets = [0.0, 0.1, 0.2, 0.4, 0.8]
# π§Ύ Output file name
output_filename = "3DPrintedMetricThreads.xml"
# π Metadata for the thread type
thread_name = "3D-Printed Metric Threads V3"
unit = "mm"
thread_angle = 60.0 # Standard ISO metric thread angle
# ============================================================
# π« USER INPUT SECTION β END HERE
# You don't need to change anything below this line
# ============================================================
import math
import xml.etree.ElementTree as ET
from abc import ABC, abstractmethod
# π’ Generate pitch values from user-defined range
def generate_pitch_list(start, end, step):
pitches = []
current = start
while current <= end + 1e-9:
pitches.append(round(current, 4))
current += step
return pitches
# π§Ό Format numbers for display (e.g., 5.0 β "5")
def format_number(val):
return str(int(val)) if val == int(val) else str(val)
# π§΅ Thread object to store calculated dimensions
class Thread:
def __init__(self):
self.gender = None
self.thread_class = None
self.major_dia = 0.0
self.pitch_dia = 0.0
self.minor_dia = 0.0
self.tap_drill = None
# π§© Abstract base class for thread profiles
class ThreadProfile(ABC):
@abstractmethod
def sizes(self):
pass
@abstractmethod
def designations(self, size):
pass
@abstractmethod
def threads(self, designation):
pass
# π§΅ Metric thread generator class
class MetricThreadGenerator(ThreadProfile):
class Designation:
def __init__(self, diameter, pitch):
self.nominal_diameter = diameter
self.pitch = pitch
self.name = f"M{format_number(diameter)}x{format_number(pitch)}"
def __init__(self, pitch_list):
self.pitches = pitch_list
def sizes(self):
return thread_sizes
def designations(self, size):
return [self.Designation(size, pitch) for pitch in self.pitches]
def threads(self, designation):
threads = []
P = designation.pitch
D = designation.nominal_diameter
H = (P / 2) / math.tan(math.radians(thread_angle / 2))
pitch_dia = D - 2 * (3 * H / 8)
minor_dia = D - 2 * (5 * H / 8)
for offset in tolerance_offsets:
class_label = f"O.{str(offset)[2:]}" # e.g., 0.1 β "O.1"
# External thread
ext = Thread()
ext.gender = "external"
ext.thread_class = class_label
ext.major_dia = D - offset
ext.pitch_dia = pitch_dia - offset
ext.minor_dia = minor_dia - offset
threads.append(ext)
# Internal thread
int_thread = Thread()
int_thread.gender = "internal"
int_thread.thread_class = class_label
int_thread.major_dia = D + offset
int_thread.pitch_dia = pitch_dia + offset
int_thread.minor_dia = minor_dia + offset
int_thread.tap_drill = D - P
threads.append(int_thread)
return threads
# π§Ύ XML generator function
def generate_xml():
pitch_list = generate_pitch_list(pitch_start, pitch_end, pitch_step)
profile = MetricThreadGenerator(pitch_list)
root = ET.Element("ThreadType")
tree = ET.ElementTree(root)
# Add metadata
ET.SubElement(root, "Name").text = thread_name
ET.SubElement(root, "CustomName").text = thread_name
ET.SubElement(root, "Unit").text = unit
ET.SubElement(root, "Angle").text = str(thread_angle)
ET.SubElement(root, "SortOrder").text = "3"
# Add thread sizes and designations
for size in profile.sizes():
size_elem = ET.SubElement(root, "ThreadSize")
ET.SubElement(size_elem, "Size").text = str(size)
for designation in profile.designations(size):
des_elem = ET.SubElement(size_elem, "Designation")
ET.SubElement(des_elem, "ThreadDesignation").text = designation.name
ET.SubElement(des_elem, "CTD").text = designation.name
ET.SubElement(des_elem, "Pitch").text = str(designation.pitch)
for thread in profile.threads(designation):
thread_elem = ET.SubElement(des_elem, "Thread")
ET.SubElement(thread_elem, "Gender").text = thread.gender
ET.SubElement(thread_elem, "Class").text = thread.thread_class
ET.SubElement(thread_elem, "MajorDia").text = f"{thread.major_dia:.4g}"
ET.SubElement(thread_elem, "PitchDia").text = f"{thread.pitch_dia:.4g}"
ET.SubElement(thread_elem, "MinorDia").text = f"{thread.minor_dia:.4g}"
if thread.tap_drill is not None:
ET.SubElement(thread_elem, "TapDrill").text = f"{thread.tap_drill:.4g}"
ET.indent(tree)
tree.write(output_filename, encoding="UTF-8", xml_declaration=True)
# π Run the generator
if __name__ == "__main__":
generate_xml()
print(f"β
XML file '{output_filename}' created for pitches from {pitch_start} mm to {pitch_end} mm in {pitch_step} mm steps.")