mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-03 18:45:55 +00:00
Tapped holes: Rc and NPT take the tap maker's tabulated drill
The Rc and NPT drills were rounded to a drill series from a third-party reproduction of DIN 345 and a fractional/letter inch series cited from memory. They now come from the same tap maker's catalogue the G and Rp drills do: Yamawa YEU23, printed p.709 (Rc, the maximum straight bored hole with non-full threads, Rc 1/16 to 4) and p.710 (NPT, the maximum straight bored hole, 1/16 to 3). A size its tables lack (Rc 5 and 6, NPT 3 1/2 to 12) is refused as a tapped hole, naming the range. The dialog's tooltip keeps the standard's minor diameter where the thread ends. Rc 1/2 drills 17.6 mm (minor 17.807), 1/2 NPT 17.60 mm (minor 17.473). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LUXeKMoxpM7Vuv8Rb6E3K2
This commit is contained in:
@@ -4,48 +4,48 @@
|
||||
"thread.form_bspt": "Pipe taper R, Rc (ISO 7-1)",
|
||||
"thread.form_npt": "Pipe taper NPT (ASME B1.20.1)",
|
||||
"thread.form_rp": "Pipe Rp (ISO 7-1)",
|
||||
"thread.taper_drill_exact": "The standard's minor diameter where the thread ends is {exact} mm; this is the stocked drill under it"
|
||||
"thread.taper_drill_exact": "The standard's minor diameter where the thread ends is {exact} mm; the drill is the tap maker's recommendation"
|
||||
},
|
||||
"ar": {
|
||||
"thread.form_bspp": "سن أنابيب G (ISO 228-1)",
|
||||
"thread.form_bspt": "سن أنابيب مخروطي R، Rc (ISO 7-1)",
|
||||
"thread.form_npt": "سن أنابيب مخروطي NPT (ASME B1.20.1)",
|
||||
"thread.form_rp": "سن أنابيب داخلي متوازٍ Rp (ISO 7-1)",
|
||||
"thread.taper_drill_exact": "القطر الأصغر القياسي عند نهاية السن {exact} مم؛ هذا هو المثقاب المتوفر الأصغر منه مباشرة"
|
||||
"thread.taper_drill_exact": "القطر الأصغر القياسي عند نهاية السن {exact} مم؛ المثقاب هو ما يوصي به صانع اللقمة"
|
||||
},
|
||||
"he": {
|
||||
"thread.form_bspp": "תבריג צנרת G (ISO 228-1)",
|
||||
"thread.form_bspt": "תבריג צנרת קוני R, Rc (ISO 7-1)",
|
||||
"thread.form_npt": "תבריג צנרת קוני NPT (ASME B1.20.1)",
|
||||
"thread.form_rp": "תבריג צנרת פנימי מקביל Rp (ISO 7-1)",
|
||||
"thread.taper_drill_exact": "הקוטר הקטן התקני בסוף התבריג הוא {exact} מ\"מ; זהו המקדח המלאי שמתחתיו"
|
||||
"thread.taper_drill_exact": "הקוטר הקטן התקני בסוף התבריג הוא {exact} מ\"מ; המקדח הוא המלצת יצרן המברז"
|
||||
},
|
||||
"ja": {
|
||||
"thread.form_bspp": "管用平行ねじ G(ISO 228-1)",
|
||||
"thread.form_bspt": "管用テーパねじ R、Rc(ISO 7-1)",
|
||||
"thread.form_npt": "管用テーパねじ NPT(ASME B1.20.1)",
|
||||
"thread.form_rp": "管用平行めねじ Rp(ISO 7-1)",
|
||||
"thread.taper_drill_exact": "ねじ終端での規格の谷径は {exact} mm です。これはそれ以下で最も近い市販ドリルです"
|
||||
"thread.taper_drill_exact": "ねじ終端での規格の谷径は {exact} mm です。下穴ドリルはタップメーカーの推奨値です"
|
||||
},
|
||||
"zh": {
|
||||
"thread.form_bspp": "管螺纹 G(ISO 228-1)",
|
||||
"thread.form_bspt": "圆锥管螺纹 R、Rc(ISO 7-1)",
|
||||
"thread.form_npt": "圆锥管螺纹 NPT(ASME B1.20.1)",
|
||||
"thread.form_rp": "圆柱内管螺纹 Rp(ISO 7-1)",
|
||||
"thread.taper_drill_exact": "螺纹终端处的标准小径为 {exact} mm;这是不大于它的常备钻头"
|
||||
"thread.taper_drill_exact": "螺纹终端处的标准小径为 {exact} mm;钻头为丝锥制造商的推荐值"
|
||||
},
|
||||
"de": {
|
||||
"thread.form_bspp": "Rohrgewinde G (ISO 228-1)",
|
||||
"thread.form_bspt": "Kegeliges Rohrgewinde R, Rc (ISO 7-1)",
|
||||
"thread.form_npt": "Kegeliges Rohrgewinde NPT (ASME B1.20.1)",
|
||||
"thread.form_rp": "Zylindrisches Innenrohrgewinde Rp (ISO 7-1)",
|
||||
"thread.taper_drill_exact": "Der genormte Kerndurchmesser am Gewindeende ist {exact} mm; dies ist der nächstkleinere Lagerbohrer"
|
||||
"thread.taper_drill_exact": "Der genormte Kerndurchmesser am Gewindeende ist {exact} mm; der Bohrer ist die Empfehlung des Gewindebohrerherstellers"
|
||||
},
|
||||
"ko": {
|
||||
"thread.form_bspp": "관용 평행나사 G (ISO 228-1)",
|
||||
"thread.form_bspt": "관용 테이퍼나사 R, Rc (ISO 7-1)",
|
||||
"thread.form_npt": "관용 테이퍼나사 NPT (ASME B1.20.1)",
|
||||
"thread.form_rp": "관용 평행 암나사 Rp (ISO 7-1)",
|
||||
"thread.taper_drill_exact": "나사 끝에서의 규격 골지름은 {exact} mm이며, 이는 그 이하의 가장 가까운 상용 드릴입니다"
|
||||
"thread.taper_drill_exact": "나사 끝에서의 규격 골지름은 {exact} mm이며, 드릴은 탭 제조사의 권장값입니다"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ mod points;
|
||||
mod profile_refs;
|
||||
pub mod progress;
|
||||
mod thread_catalog;
|
||||
pub use thread_catalog::{TappedThread, TappedThreadFamily, parse_tapped_thread, tapped_thread_sizes};
|
||||
pub use thread_catalog::{TaperDrill, TappedThread, TappedThreadFamily, parse_tapped_thread, tapped_thread_sizes, untabulated_taper_tap};
|
||||
mod walk;
|
||||
pub use profile_refs::{capture_profile_selection, profile_fallback_notes, profile_selection_indices, profile_selection_indices_lenient};
|
||||
pub mod plastic;
|
||||
|
||||
+100
-132
@@ -46,138 +46,108 @@ fn pipe_size(size: crate::pipe_thread_catalog::PipeThread) -> TappedThread {
|
||||
}
|
||||
}
|
||||
|
||||
/// The drill of an internal taper thread (Rc, NPT): `exact` is the standard's internal minor
|
||||
/// diameter where the thread ends (mm), the reference plane's minor at the face (d - 2h for ISO
|
||||
/// 7-1, E1 - h for NPT) less the 1 in 16 taper over the thread's length (ISO 7-1's useful thread,
|
||||
/// NPT's effective thread L2), so a tap cuts full form over the whole length. The hole is
|
||||
/// drilled with the largest stocked drill not larger than that (`name`, `diameter`): metric for
|
||||
/// Rc, inch for NPT. Above the drill series it is bored to `exact` (no `name`).
|
||||
/// The drill of an internal taper thread (Rc, NPT). `diameter` is the tap maker's tabulated
|
||||
/// drill for a straight (not reamed) hole; `exact` is the standard's internal minor diameter where
|
||||
/// the thread ends (mm), the reference plane's minor at the face (d - 2h for ISO 7-1, E1 - h for
|
||||
/// NPT) less the 1 in 16 taper over the thread's length (ISO 7-1's useful thread, NPT's effective
|
||||
/// thread L2), which the dialog shows beside it.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct TaperDrill {
|
||||
pub exact: f64,
|
||||
pub diameter: f64,
|
||||
pub name: Option<String>,
|
||||
}
|
||||
|
||||
/// Metric twist drill diameters (mm), DIN 345:2006 (taper shank twist drills, the series up to
|
||||
/// 100 mm), as reproduced at <https://www.fasten.it/en/Norms/Norm/DIN%20345>; three digits that
|
||||
/// reproduction drops are restored from their neighbours (15.25, 34.5, 54).
|
||||
const DIN_345: &[f64] = &[
|
||||
3.0, 3.2, 3.5, 3.8, 4.0, 4.2, 4.5, 4.8, 5.0, 5.2, 5.5, 5.8, 6.0, 6.2, 6.5, 6.8, 7.0, 7.2, 7.5, 7.8, 8.0, 8.2, 8.5, 8.8, 9.0, 9.2, 9.5, 9.8, 10.0,
|
||||
10.2, 10.5, 10.8, 11.0, 11.2, 11.5, 11.8, 12.0, 12.2, 12.5, 12.8, 13.0, 13.2, 13.5, 13.8, 14.0, 14.25, 14.5, 14.75, 15.0, 15.25, 15.5, 15.75,
|
||||
16.0, 16.25, 16.5, 16.75, 17.0, 17.25, 17.5, 17.75, 18.0, 18.25, 18.5, 18.75, 19.0, 19.25, 19.5, 19.75, 20.0, 20.25, 20.5, 20.75, 21.0, 21.25,
|
||||
21.5, 21.75, 22.0, 22.25, 22.5, 22.75, 23.0, 23.25, 23.5, 23.75, 24.0, 24.25, 24.5, 24.75, 25.0, 25.25, 25.5, 25.75, 26.0, 26.25, 26.5, 26.75,
|
||||
27.25, 27.5, 27.75, 28.0, 28.25, 28.5, 28.75, 29.0, 29.25, 29.5, 29.75, 30.0, 30.25, 30.5, 30.75, 31.0, 31.25, 31.5, 31.75, 32.0, 32.5, 33.0,
|
||||
33.5, 34.5, 35.0, 35.5, 36.0, 36.5, 37.0, 37.5, 38.0, 38.5, 39.0, 39.5, 40.0, 40.5, 41.0, 41.5, 42.0, 42.5, 43.0, 43.5, 44.0, 44.5, 45.0, 45.5,
|
||||
46.0, 46.5, 47.0, 47.5, 48.0, 48.5, 49.0, 49.5, 50.0, 50.5, 51.0, 52.0, 53.0, 54.0, 55.0, 56.0, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0, 63.0, 64.0,
|
||||
65.0, 66.0, 67.0, 68.0, 69.0, 70.0, 71.0, 72.0, 73.0, 74.0, 76.0, 77.0, 78.0, 79.0, 80.0, 81.0, 82.0, 83.0, 84.0, 85.0, 86.0, 87.0, 88.0, 89.0,
|
||||
90.0, 91.0, 92.0, 93.0, 94.0, 95.0, 96.0, 97.0, 98.0, 99.0, 100.0,
|
||||
/// Rc (ISO 7-1, "PT") drills: Yamawa YEU23, printed p.709 ("Taper Internal Pipe Threads -
|
||||
/// Rc(BSPT)-PT"), the maximum size of a straight bored hole when the threads have non-full
|
||||
/// threads (the same values as the Rc tap's bored hole A on printed p.121), for the sizes of
|
||||
/// ISO 7-1's table it lists (1/16 to 4).
|
||||
/// <https://www.yamawa.eu/files/Yamawa_European_Catalogue_YEU23.pdf>
|
||||
const RC_DRILLS: &[(&str, f64)] = &[
|
||||
("1/16", 6.1),
|
||||
("1/8", 8.1),
|
||||
("1/4", 10.7),
|
||||
("3/8", 14.2),
|
||||
("1/2", 17.6),
|
||||
("3/4", 23.0),
|
||||
("1", 29.0),
|
||||
("1 1/4", 37.6),
|
||||
("1 1/2", 43.5),
|
||||
("2", 55.0),
|
||||
("2 1/2", 70.3),
|
||||
("3", 82.8),
|
||||
("4", 107.6),
|
||||
];
|
||||
|
||||
/// Letter drill sizes (in), ASME B94.11M (twist drills).
|
||||
const LETTER_DRILLS: &[(char, f64)] = &[
|
||||
('A', 0.234),
|
||||
('B', 0.238),
|
||||
('C', 0.242),
|
||||
('D', 0.246),
|
||||
('E', 0.250),
|
||||
('F', 0.257),
|
||||
('G', 0.261),
|
||||
('H', 0.266),
|
||||
('I', 0.272),
|
||||
('J', 0.277),
|
||||
('K', 0.281),
|
||||
('L', 0.290),
|
||||
('M', 0.295),
|
||||
('N', 0.302),
|
||||
('O', 0.316),
|
||||
('P', 0.323),
|
||||
('Q', 0.332),
|
||||
('R', 0.339),
|
||||
('S', 0.348),
|
||||
('T', 0.358),
|
||||
('U', 0.368),
|
||||
('V', 0.377),
|
||||
('W', 0.386),
|
||||
('X', 0.397),
|
||||
('Y', 0.404),
|
||||
('Z', 0.413),
|
||||
/// NPT drills: Yamawa YEU23, printed p.710 ("American Taper Pipe Threads (NPT)", referring to
|
||||
/// ASME B1.20.1), the maximum size of a straight bored hole, 1/16 to 3.
|
||||
const NPT_DRILLS: &[(&str, f64)] = &[
|
||||
("1/16", 6.05),
|
||||
("1/8", 8.39),
|
||||
("1/4", 10.85),
|
||||
("3/8", 14.27),
|
||||
("1/2", 17.60),
|
||||
("3/4", 22.91),
|
||||
("1", 28.78),
|
||||
("1 1/4", 37.50),
|
||||
("1 1/2", 43.57),
|
||||
("2", 55.58),
|
||||
("2 1/2", 66.28),
|
||||
("3", 82.05),
|
||||
];
|
||||
|
||||
/// Fractional drill sizes by 64ths of an inch up to this many 64ths (1 1/2 in), ASME B94.11M.
|
||||
const FRACTIONAL_64THS: u32 = 96;
|
||||
|
||||
/// A fraction of an inch in lowest terms: `11/16 in`, `1 1/4 in`.
|
||||
fn inch_fraction(n64: u32) -> String {
|
||||
let (whole, mut num, mut den) = (n64 / 64, n64 % 64, 64);
|
||||
while num > 0 && num % 2 == 0 {
|
||||
num /= 2;
|
||||
den /= 2;
|
||||
}
|
||||
match (whole, num) {
|
||||
(0, _) => format!("{num}/{den} in"),
|
||||
(w, 0) => format!("{w} in"),
|
||||
(w, _) => format!("{w} {num}/{den} in"),
|
||||
}
|
||||
/// The drill of an Rc or NPT size the tap maker tabulates; none for the others.
|
||||
fn taper_drill(family: TappedThreadFamily, size: &crate::pipe_thread_sizes::PipeSize) -> Option<TaperDrill> {
|
||||
let (table, h) = match family {
|
||||
TappedThreadFamily::Npt => (NPT_DRILLS, crate::pipe_thread_sizes::NPT_HEIGHT * size.pitch()),
|
||||
_ => (RC_DRILLS, 0.640327 * size.pitch()),
|
||||
};
|
||||
let diameter = table.iter().find(|(n, _)| *n == size.nominal)?.1;
|
||||
Some(TaperDrill { exact: size.major - 2.0 * h - size.length / 16.0, diameter })
|
||||
}
|
||||
|
||||
/// The largest stocked drill not larger than `exact` mm: metric (DIN 345) or inch (letter and
|
||||
/// fractional drills, ASME B94.11M). None past the series.
|
||||
fn stocked_drill(exact: f64, inch: bool) -> Option<(f64, String)> {
|
||||
let fits = |d: f64| d <= exact + 1e-9;
|
||||
if !inch {
|
||||
let max = DIN_345.iter().copied().fold(0.0, f64::max);
|
||||
if exact > max + 1.0 {
|
||||
return None;
|
||||
}
|
||||
return DIN_345
|
||||
.iter()
|
||||
.copied()
|
||||
.filter(|d| fits(*d))
|
||||
.fold(None, |a: Option<f64>, d| Some(a.map_or(d, |a| a.max(d))))
|
||||
.map(|d| (d, format!("{d} mm")));
|
||||
}
|
||||
if exact > f64::from(FRACTIONAL_64THS) / 64.0 * 25.4 + 25.4 / 64.0 {
|
||||
return None;
|
||||
}
|
||||
let letters = LETTER_DRILLS.iter().map(|(c, d)| (d * 25.4, format!("{c} ({d:.3} in)")));
|
||||
let fractions = (1..=FRACTIONAL_64THS).map(|n| (f64::from(n) / 64.0 * 25.4, inch_fraction(n)));
|
||||
letters.chain(fractions).filter(|(d, _)| fits(*d)).max_by(|a, b| a.0.total_cmp(&b.0))
|
||||
}
|
||||
|
||||
/// The drill of an Rc or NPT size ([`TaperDrill`]).
|
||||
fn taper_drill(family: TappedThreadFamily, size: &crate::pipe_thread_sizes::PipeSize) -> TaperDrill {
|
||||
let p = size.pitch();
|
||||
let h = if family == TappedThreadFamily::Npt { crate::pipe_thread_sizes::NPT_HEIGHT * p } else { 0.640327 * p };
|
||||
let exact = size.major - 2.0 * h - size.length / 16.0;
|
||||
match stocked_drill(exact, family == TappedThreadFamily::Npt) {
|
||||
Some((diameter, name)) => TaperDrill { exact, diameter, name: Some(name) },
|
||||
None => TaperDrill { exact, diameter: (exact * 1000.0).floor() / 1000.0, name: None },
|
||||
/// The pipe sizes of a taper family.
|
||||
fn taper_sizes(family: TappedThreadFamily) -> Vec<crate::pipe_thread_sizes::PipeSize> {
|
||||
match family {
|
||||
TappedThreadFamily::Rc => crate::pipe_thread_sizes::iso_7_1().collect(),
|
||||
TappedThreadFamily::Npt => crate::pipe_thread_sizes::npt().collect(),
|
||||
_ => Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
impl TappedThread {
|
||||
/// An Rc or NPT size's drill: the standard's exact value and the stocked drill it is.
|
||||
/// An Rc or NPT size's drill: the tap maker's and the standard's exact value.
|
||||
pub fn taper_drill(&self) -> Option<TaperDrill> {
|
||||
let sizes = match self.family {
|
||||
TappedThreadFamily::Rc => crate::pipe_thread_sizes::iso_7_1().collect::<Vec<_>>(),
|
||||
TappedThreadFamily::Npt => crate::pipe_thread_sizes::npt().collect(),
|
||||
_ => return None,
|
||||
};
|
||||
sizes.iter().find(|z| (z.major - self.major_diameter).abs() < 1e-9).map(|z| taper_drill(self.family, z))
|
||||
taper_sizes(self.family).iter().find(|z| (z.major - self.major_diameter).abs() < 1e-9).and_then(|z| taper_drill(self.family, z))
|
||||
}
|
||||
}
|
||||
|
||||
/// Why an Rc or NPT designation is no tapped hole's: a size of its standard the tap maker's table
|
||||
/// has no drill for. None for any other text.
|
||||
pub fn untabulated_taper_tap(text: &str) -> Option<String> {
|
||||
use crate::thread_forms::ThreadForm;
|
||||
let (family, form, listed) = match ThreadForm::of_designation(text) {
|
||||
Some(ThreadForm::Bspt) if ThreadForm::pipe_internal(text) => (TappedThreadFamily::Rc, ThreadForm::Bspt, "Rc 1/16 to Rc 4"),
|
||||
Some(ThreadForm::Npt) => (TappedThreadFamily::Npt, ThreadForm::Npt, "1/16 to 3 NPT"),
|
||||
_ => return None,
|
||||
};
|
||||
let size = form.parse(text, 1).ok()?;
|
||||
let z = taper_sizes(family).into_iter().find(|z| (z.major - size.major).abs() < 1e-9)?;
|
||||
taper_drill(family, &z).is_none().then(|| {
|
||||
format!("no tap drill is tabulated for `{}` (Yamawa's table, which the tapped-hole drills come from, lists {listed}): it is not offered as a tapped hole", text.trim())
|
||||
})
|
||||
}
|
||||
|
||||
/// An internal taper thread (Rc, NPT) of the size tables a modelled thread cuts
|
||||
/// ([`crate::pipe_thread_sizes`]), drilled with [`TaperDrill`]'s stocked drill.
|
||||
fn taper_size(family: TappedThreadFamily, size: crate::pipe_thread_sizes::PipeSize) -> TappedThread {
|
||||
/// ([`crate::pipe_thread_sizes`]), drilled with the tap maker's drill ([`TaperDrill`]); none for
|
||||
/// a size without one.
|
||||
fn taper_size(family: TappedThreadFamily, size: crate::pipe_thread_sizes::PipeSize) -> Option<TappedThread> {
|
||||
use crate::thread_forms::ThreadForm;
|
||||
let p = size.pitch();
|
||||
let form = if family == TappedThreadFamily::Npt { ThreadForm::Npt } else { ThreadForm::Bspt };
|
||||
let designation = form.format(size.major, p, p);
|
||||
let designation = if form == ThreadForm::Bspt { designation.replacen("R ", "Rc ", 1) } else { designation };
|
||||
let tap_drill = taper_drill(family, &size).diameter;
|
||||
TappedThread { family, designation, major_diameter: size.major, pitch: p, tap_drill }
|
||||
let tap_drill = taper_drill(family, &size)?.diameter;
|
||||
Some(TappedThread { family, designation, major_diameter: size.major, pitch: p, tap_drill })
|
||||
}
|
||||
|
||||
// Diameter/pitch pairs verified against Guhring, plus Yamawa for M12x1.25.
|
||||
@@ -249,8 +219,7 @@ pub fn tapped_thread_sizes(family: TappedThreadFamily) -> Vec<TappedThread> {
|
||||
return crate::pipe_thread_catalog::pipe_thread_sizes().map(pipe_size).filter(|s| s.family == family).collect();
|
||||
}
|
||||
match family {
|
||||
TappedThreadFamily::Rc => return crate::pipe_thread_sizes::iso_7_1().map(|z| taper_size(family, z)).collect(),
|
||||
TappedThreadFamily::Npt => return crate::pipe_thread_sizes::npt().map(|z| taper_size(family, z)).collect(),
|
||||
TappedThreadFamily::Rc | TappedThreadFamily::Npt => return taper_sizes(family).into_iter().filter_map(|z| taper_size(family, z)).collect(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
@@ -274,8 +243,8 @@ pub fn tapped_thread_sizes(family: TappedThreadFamily) -> Vec<TappedThread> {
|
||||
}
|
||||
|
||||
/// Explicit metric custom sizes remain supported. Unified sizes must be in the verified
|
||||
/// catalogue and include their UNC/UNF suffix. G/Rp use explicit process drills, Rc/NPT the drill
|
||||
/// derived from their standards ([`taper_size`]).
|
||||
/// catalogue and include their UNC/UNF suffix. G/Rp use explicit process drills, Rc/NPT the tap
|
||||
/// maker's tabulated drills ([`TaperDrill`]); an Rc or NPT size without one is none.
|
||||
pub fn parse_tapped_thread(text: &str) -> Option<TappedThread> {
|
||||
if text.len() > 128 {
|
||||
return None;
|
||||
@@ -319,36 +288,35 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// Rc and NPT holes: the size tables' diameters, and the stocked drill just under the internal
|
||||
/// minor where the thread ends (Rc 1/2: d1 18.631 at the face less 13.2 mm of useful thread at
|
||||
/// 1 in 16, 17.807, drilled 17.75 mm; 1/2 NPT: E1 - h = 0.77843 - 0.05714 in at the face less
|
||||
/// L2 = 0.5337 in at 1 in 16, 0.6879 in, drilled 11/16 in), and no external R.
|
||||
/// Rc and NPT holes: the size tables' diameters, the tap maker's drill (Yamawa YEU23 pp.709
|
||||
/// and 710) and the standard's minor where the thread ends (Rc 1/2: d1 18.631 at the face less
|
||||
/// 13.2 mm of useful thread at 1 in 16; 1/2 NPT: E1 - h = 0.77843 - 0.05714 in at the face less
|
||||
/// L2 = 0.5337 in at 1 in 16), a size without a tabulated drill refused, and no external R.
|
||||
#[test]
|
||||
fn internal_taper_threads_drill_to_their_minor_where_the_thread_ends() {
|
||||
fn internal_taper_threads_take_the_tap_makers_drill() {
|
||||
let rc = parse_tapped_thread("Rc1/2").unwrap();
|
||||
assert_eq!((rc.family, rc.designation.as_str(), rc.major_diameter), (TappedThreadFamily::Rc, "Rc 1/2", 20.955));
|
||||
assert_eq!((rc.family, rc.designation.as_str(), rc.major_diameter, rc.tap_drill), (TappedThreadFamily::Rc, "Rc 1/2", 20.955, 17.6));
|
||||
let d = rc.taper_drill().unwrap();
|
||||
assert!((d.exact - (18.631 - 13.2 / 16.0)).abs() < 2e-3, "{d:?}");
|
||||
assert_eq!((rc.tap_drill, d.name.as_deref()), (17.75, Some("17.75 mm")));
|
||||
let npt = parse_tapped_thread("1/2 NPT").unwrap();
|
||||
assert_eq!((npt.family, npt.designation.as_str()), (TappedThreadFamily::Npt, "1/2-14 NPT"));
|
||||
assert_eq!((npt.family, npt.designation.as_str(), npt.tap_drill), (TappedThreadFamily::Npt, "1/2-14 NPT", 17.6));
|
||||
let d = npt.taper_drill().unwrap();
|
||||
assert!((d.exact - (0.77843 - 0.8 / 14.0 - 0.5337 / 16.0) * 25.4).abs() < 2e-3, "{d:?}");
|
||||
assert_eq!((npt.tap_drill, d.name.as_deref()), (11.0 / 16.0 * 25.4, Some("11/16 in")));
|
||||
// A letter drill where it is the closer stocked size (1/8 NPT), and a bore past the series.
|
||||
let small = parse_tapped_thread("1/8 NPT").unwrap().taper_drill().unwrap();
|
||||
assert!(small.diameter <= small.exact && small.name.is_some(), "{small:?}");
|
||||
let large = parse_tapped_thread("Rc 6").unwrap().taper_drill().unwrap();
|
||||
assert!(large.name.is_none() && (large.diameter - large.exact).abs() < 1e-3, "{large:?}");
|
||||
for family in [TappedThreadFamily::Rc, TappedThreadFamily::Npt] {
|
||||
for s in tapped_thread_sizes(family) {
|
||||
let d = s.taper_drill().unwrap();
|
||||
assert!(d.diameter <= d.exact + 1e-9 && d.exact - d.diameter < 0.02 * d.exact + 0.4, "{}: {d:?}", s.designation);
|
||||
}
|
||||
}
|
||||
assert_eq!(rc.profile_degrees(), 55.0);
|
||||
assert_eq!(npt.profile_degrees(), 60.0);
|
||||
assert!(parse_tapped_thread("R 1/2").is_none(), "an external taper thread is no hole's");
|
||||
for untabulated in ["Rc 5", "Rc 6", "4-8 NPT", "12 NPT"] {
|
||||
assert!(parse_tapped_thread(untabulated).is_none(), "{untabulated}");
|
||||
assert!(untabulated_taper_tap(untabulated).is_some_and(|e| e.contains("no tap drill is tabulated")), "{untabulated}");
|
||||
}
|
||||
assert!(untabulated_taper_tap("Rc 1/2").is_none() && untabulated_taper_tap("M8").is_none());
|
||||
// Each tabulated drill lies within a pitch of the standard's minor where the thread ends.
|
||||
for family in [TappedThreadFamily::Rc, TappedThreadFamily::Npt] {
|
||||
for s in tapped_thread_sizes(family) {
|
||||
let d = s.taper_drill().unwrap();
|
||||
assert!((d.diameter - d.exact).abs() < s.pitch, "{}: {d:?}", s.designation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -367,8 +335,8 @@ mod tests {
|
||||
let count = match family {
|
||||
TappedThreadFamily::Metric => sizes.len(),
|
||||
TappedThreadFamily::G | TappedThreadFamily::Rp => 6,
|
||||
TappedThreadFamily::Rc => 15,
|
||||
TappedThreadFamily::Npt => crate::pipe_thread_sizes::npt().count(),
|
||||
TappedThreadFamily::Rc => RC_DRILLS.len(),
|
||||
TappedThreadFamily::Npt => NPT_DRILLS.len(),
|
||||
_ => 14,
|
||||
};
|
||||
assert_eq!(sizes.len(), count, "{family:?}");
|
||||
|
||||
@@ -69,7 +69,7 @@ pub static COMMANDS: &[CommandSpec] = &[
|
||||
.at("SOLID", "CREATE")
|
||||
.icon("hole")
|
||||
.key("H")
|
||||
.params("position: [x,y,z] on a face (numbers, or length expressions the hole follows) | sketch + points: [sketch point ids] (one hole each, perpendicular to the sketch, into the material on whichever side of the sketch plane it is) | sketch alone (every sketch point: standalone points and circle centres); flip?: bool (sketch points: drill to the other side); single?: bool (with one sketch point: a Single hole that follows the point, drilled into the face there); direction?: [x,y,z] (default: into the face, against its outward normal; one that leaves the face is mirrored into it; ignored with sketch points unless single); diameter | thread (a tapped hole: metric major minus pitch or tabulated UNC/UNF, G or Rp cut-tap drill, or the Rc/NPT drill to the internal minor diameter where the thread ends) | clearance: \"M6\" with fit?: close|normal|loose (ISO 273); depth? (default through all) | to?: [x,y,z] (To Object: drill to that face or point); references?: [{edge: [x,y,z] on a straight edge of the face, distance: expr}] (at most two; the centre goes that far from each edge's line, in the face's plane, and follows the edges; with a numeric position only); type?: simple|drilled|counterbore|countersink; tip_angle?; cb_diameter?, cb_depth?; cs_diameter?, cs_angle?; thread?: \"M6\", \"1/4-20 UNC\", \"G 1/4\", \"Rp 1/4\", \"Rc 1/4\" or \"1/4-18 NPT\" (cosmetic unless modeled); hand?: right|left (the tapped thread's hand; default right; needs thread); thread_depth?: positive length independent of drill depth (default: full useful cylindrical wall; must fit that wall); modeled?: bool (needs thread: the tapped thread cut into the wall, the groove between its teeth, as solid.thread's modelled one; default false: listed only); ease_out?: expr|standard|short (modelled tapped threads: the inner end, towards the bottom, fades out over this length, ISO 3508's runout, standard 2.5 P, short 1.25 P; without it the groove stops square at thread_depth, or clear of a blind hole's bottom); targets?: [body] (the bodies to drill; holes at the points of a sketch on a body's face default to that body, found along the holes' direction on it alone; explicit targets or participants override, [\"*\"] every body)"),
|
||||
.params("position: [x,y,z] on a face (numbers, or length expressions the hole follows) | sketch + points: [sketch point ids] (one hole each, perpendicular to the sketch, into the material on whichever side of the sketch plane it is) | sketch alone (every sketch point: standalone points and circle centres); flip?: bool (sketch points: drill to the other side); single?: bool (with one sketch point: a Single hole that follows the point, drilled into the face there); direction?: [x,y,z] (default: into the face, against its outward normal; one that leaves the face is mirrored into it; ignored with sketch points unless single); diameter | thread (a tapped hole: metric major minus pitch or tabulated UNC/UNF, G or Rp cut-tap drill, or the Rc/NPT tap maker's tabulated drill, Rc 1/16 to 4 and NPT 1/16 to 3) | clearance: \"M6\" with fit?: close|normal|loose (ISO 273); depth? (default through all) | to?: [x,y,z] (To Object: drill to that face or point); references?: [{edge: [x,y,z] on a straight edge of the face, distance: expr}] (at most two; the centre goes that far from each edge's line, in the face's plane, and follows the edges; with a numeric position only); type?: simple|drilled|counterbore|countersink; tip_angle?; cb_diameter?, cb_depth?; cs_diameter?, cs_angle?; thread?: \"M6\", \"1/4-20 UNC\", \"G 1/4\", \"Rp 1/4\", \"Rc 1/4\" or \"1/4-18 NPT\" (cosmetic unless modeled); hand?: right|left (the tapped thread's hand; default right; needs thread); thread_depth?: positive length independent of drill depth (default: full useful cylindrical wall; must fit that wall); modeled?: bool (needs thread: the tapped thread cut into the wall, the groove between its teeth, as solid.thread's modelled one; default false: listed only); ease_out?: expr|standard|short (modelled tapped threads: the inner end, towards the bottom, fades out over this length, ISO 3508's runout, standard 2.5 P, short 1.25 P; without it the groove stops square at thread_depth, or clear of a blind hole's bottom); targets?: [body] (the bodies to drill; holes at the points of a sketch on a body's face default to that body, found along the holes' direction on it alone; explicit targets or participants override, [\"*\"] every body)"),
|
||||
CommandSpec::new("solid.pipe", "Pipe", pipe)
|
||||
.at("SOLID", "CREATE")
|
||||
.icon("pipe")
|
||||
@@ -2434,7 +2434,9 @@ fn hole(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
{
|
||||
return Err(bad(
|
||||
cmd,
|
||||
fine_only_hint(t).unwrap_or_else(|| format!("unknown tapped thread `{t}` (ISO metric or a catalogued UNC/UNF, G, Rp, Rc or NPT size)")),
|
||||
fine_only_hint(t)
|
||||
.or_else(|| solidcraft_doc::untabulated_taper_tap(t))
|
||||
.unwrap_or_else(|| format!("unknown tapped thread `{t}` (ISO metric or a catalogued UNC/UNF, G, Rp, Rc or NPT size)")),
|
||||
));
|
||||
}
|
||||
let thread_depth = match p.get("thread_depth") {
|
||||
|
||||
@@ -1216,8 +1216,8 @@ fn a_taper_pipe_thread_starts_at_a_free_end_and_is_named_for_its_side() {
|
||||
/// A tapped hole's thread cut into its wall (`modeled`), as the thread feature cuts one: an M8
|
||||
/// blind hole whose groove stops clear of the drill point's bottom, or fades out before it
|
||||
/// (`ease_out`, ISO 3508), which leaves more of the wall than the full form there; an Rc 1/2
|
||||
/// through a plate, drilled with the stocked drill under its minor where the thread ends and cut
|
||||
/// to its taper; each a valid body that reopens the same.
|
||||
/// through a plate, drilled with the tap maker's drill and cut to its taper; each a valid body
|
||||
/// that reopens the same. An Rc size with no tabulated drill is refused.
|
||||
#[test]
|
||||
fn a_modelled_tapped_hole_stops_clear_of_its_bottom_or_fades_out_before_it() {
|
||||
let blind = |extra: Value| {
|
||||
@@ -1243,9 +1243,8 @@ fn a_modelled_tapped_hole_stops_clear_of_its_bottom_or_fades_out_before_it() {
|
||||
run(&mut s, "solid.box", json!({"length":40,"width":40,"height":12,"body_name":"Plate"}));
|
||||
let out = run(&mut s, "solid.hole", json!({"position":[20,20,12],"direction":[0,0,-1],"thread":"Rc 1/2"}));
|
||||
let drilled = exact_volume(&s, "Plate");
|
||||
// d1 at the face less 13.2 mm of useful thread at 1 in 16 is 17.807 mm: the stocked drill
|
||||
// under it is 17.75 mm (DIN 345).
|
||||
let drill: f64 = 17.75;
|
||||
// The tap maker's drill for a straight Rc 1/2 hole (Yamawa YEU23 p.709).
|
||||
let drill: f64 = 17.6;
|
||||
assert!((drilled - (40.0 * 40.0 * 12.0 - PI * (drill / 2.0).powi(2) * 12.0)).abs() < 1e-3, "{drilled}");
|
||||
let id = out["feature"].as_u64().unwrap();
|
||||
let redefine = json!({"position":[20,20,12],"direction":[0,0,-1],"thread":"Rc 1/2","modeled":true});
|
||||
@@ -1256,4 +1255,5 @@ fn a_modelled_tapped_hole_stops_clear_of_its_bottom_or_fades_out_before_it() {
|
||||
let err = |p: Value| Session::default().execute("solid.hole", &p).err().map(|e| e.to_string()).unwrap_or_default();
|
||||
assert!(err(json!({"position":[0,0,0],"diameter":5,"modeled":true})).contains("`modeled` needs `thread`"));
|
||||
assert!(err(json!({"position":[0,0,0],"thread":"M8","ease_out":"standard"})).contains("modelled thread"));
|
||||
assert!(err(json!({"position":[0,0,0],"thread":"Rc 5"})).contains("no tap drill is tabulated"));
|
||||
}
|
||||
|
||||
@@ -155,16 +155,12 @@ pub(crate) fn hole_rows(ui: &mut egui::Ui, doc: &Document, designation: &mut Str
|
||||
}
|
||||
form_row(ui, "Tap drill diameter", |ui| {
|
||||
match parse_tapped_thread(designation).filter(|_| custom.as_ref().is_none_or(|draft| draft.error.is_none())) {
|
||||
// An Rc or NPT hole is drilled with the stocked drill under the standard's minor
|
||||
// diameter where the thread ends; that exact value is the tooltip.
|
||||
// An Rc or NPT hole takes the tap maker's drill; the standard's minor diameter where
|
||||
// the thread ends is the tooltip.
|
||||
Some(size) => match size.taper_drill() {
|
||||
Some(d) => {
|
||||
let shown = d
|
||||
.name
|
||||
.filter(|n| !n.ends_with(" mm"))
|
||||
.map_or_else(|| format!("{} mm", size.tap_drill), |n| format!("{} mm ({n})", size.tap_drill));
|
||||
let exact = format!("{:.3}", d.exact);
|
||||
ui.label(shown).on_hover_text(crate::i18n::format("thread.taper_drill_exact", &[("exact", &exact)]));
|
||||
ui.label(format!("{} mm", size.tap_drill)).on_hover_text(crate::i18n::format("thread.taper_drill_exact", &[("exact", &exact)]));
|
||||
}
|
||||
None => {
|
||||
ui.label(format!("{} mm", size.tap_drill));
|
||||
|
||||
+12
-19
@@ -36,18 +36,16 @@ thread classes and sealing behaviour are outside this catalogue.
|
||||
|
||||
## Taper Rc and NPT threads
|
||||
|
||||
An Rc or NPT hole is drilled with the largest stocked drill not larger than the
|
||||
internal thread's minor diameter where the thread ends: the reference plane's
|
||||
minor (d - 2h for ISO 7-1, E1 - h for NPT) at the face, less the 1 in 16 taper
|
||||
over the thread's length (ISO 7-1's useful thread, NPT's effective thread L2), so
|
||||
that the tap cuts full form over the whole length. Rc takes a metric drill of the
|
||||
DIN 345 series (to 100 mm), NPT a letter or fractional inch drill (by 64ths to
|
||||
1 1/2 in, ASME B94.11M); past the series the hole is bored to the exact value. The
|
||||
Hole dialog shows the drill and, as its tooltip, the exact value: Rc 1/2 is
|
||||
17.807 mm, drilled 17.75 mm; 1/2 NPT is 17.473 mm (0.6879 in), drilled 11/16 in
|
||||
(17.4625 mm). This is derived from the standards, not a tap maker's
|
||||
recommendation (which often allows for reaming); an explicit `diameter`
|
||||
overrides it. Listed, the hole
|
||||
An Rc or NPT hole takes the tap maker's drill for a straight (not reamed) hole:
|
||||
Yamawa YEU23's "maximum size of straight bored hole", for Rc with non-full
|
||||
threads (printed p.709, Rc 1/16 to 4) and for NPT (printed p.710, 1/16 to 3).
|
||||
A size of ISO 7-1 or ASME B1.20.1 outside those (Rc 5 and 6, NPT 3 1/2 to 12) is
|
||||
refused as a tapped hole. The Hole dialog shows the drill and, as its tooltip,
|
||||
the standard's minor diameter where the thread ends: the reference plane's minor
|
||||
(d - 2h for ISO 7-1, E1 - h for NPT) at the face less the 1 in 16 taper over the
|
||||
thread's length (ISO 7-1's useful thread, NPT's effective thread L2). Rc 1/2:
|
||||
drill 17.6 mm, minor 17.807 mm; 1/2 NPT: drill 17.60 mm, minor 17.473 mm. An
|
||||
explicit `diameter` overrides the drill. Listed, the hole
|
||||
is that cylindrical drill; modelled, the thread's taper is cut into it (the tap's
|
||||
minor cone and the helical groove).
|
||||
|
||||
@@ -78,16 +76,11 @@ cylindrical pilot plus the designation; modelled, the helical groove is cut too.
|
||||
|
||||
## Primary sources
|
||||
|
||||
- DIN 345:2006 (taper shank twist drills), the metric drill diameters to 100 mm as
|
||||
reproduced at <https://www.fasten.it/en/Norms/Norm/DIN%20345>: the stocked drills
|
||||
of Rc holes. Three digits that reproduction drops (15.25, 34.5, 54) are restored
|
||||
from their neighbours.
|
||||
- ASME B94.11M (twist drills): the letter drill sizes A to Z and fractional sizes
|
||||
by 64ths of an inch, the stocked drills of NPT holes.
|
||||
|
||||
- [Yamawa, YEU23 European catalogue](https://www.yamawa.eu/files/Yamawa_European_Catalogue_YEU23.pdf),
|
||||
printed page 668: basic G/Rp dimensions; page 707: separate G and Rp drill and
|
||||
recommended bore columns. These supply the finite parallel-pipe entries above.
|
||||
recommended bore columns; page 709: Rc drills (maximum straight bored hole);
|
||||
page 710: NPT drills. These supply the finite parallel-pipe entries above.
|
||||
|
||||
- [Guhring, Tap Drill Sizes](https://guhring.com/media/catalogs/lgbkp3ieki4.pdf),
|
||||
PDF page 2: UNC/UNF pitch and practical CUT TAPS approximately75% drills;
|
||||
|
||||
Reference in New Issue
Block a user